// Components
import vehicleParts from "@/layouts/vehicle-parts/vehicle-parts.vue";
import glassPartQuestion from "@/layouts/vehicle-parts/glass-part-question/glass-part-question";

// Supporting Files
import { settleAllPromises } from "@/helpers/layout-helper.js";
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { shallowMount } from "@vue/test-utils";
import { getMountOptions } from "@/helpers/unit-test-helper.js";
import { nextTick } from "vue";
import baseMixin from "@/mixins/base-mixin.js";
import { storeActions } from "@/constants/store-actions";
import store from "@/store";
import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
import { navigationScenarios } from "@/router/router-constants/navigation-scenarios";

// Mock our module for promises.
jest.mock("@/helpers/layout-helper.js", () => ({
    settleAllPromises: jest.fn(),
}));

// Mock fetchCmsContentForPage
jest.mock("@/helpers/cms-content-helper", () => ({
    fetchCmsContentForPage: jest.fn(),
}));

jest.mock("@/helpers/heritage-integration/navigation-helper", () => ({
    navigateToHeritageFunnel: jest.fn(),
}));

// Mock store
jest.mock(
    "@/store",
    () => {
        return {};
    },
    { virtual: true }
);

store.getters = {
    pageData: jest.fn(),
    damage: {
        isRepair: false,
    },
};

const basePartResponse = {
    partsOrQuestions: [
        {
            glassName: "Stationary",
            glassLocation: "Rear",
            parts: [
                {
                    partNumber: "DB12209GTYN",
                    description: "heated glass, solar, 1 hole",
                    color: "Green Tint",
                    requiresRecalibration: false,
                    requiresCapabilityQuestions: false,
                    childParts: null,
                },
                {
                    partNumber: "DB12209YPYNOEM",
                    description: "heated glass, solar, 1 hole",
                    color: "Gray Tint Privacy",
                    requiresRecalibration: false,
                    requiresCapabilityQuestions: false,
                    childParts: null,
                },
            ],
            partQuestions: null,
        },
    ],
};

describe("vehicle-parts.vue", () => {
    test("Set cms content called on load", (done) => {
        //Arrange
        store.getters.pageData.mockReturnValue(basePartResponse);
        store.getters.lineItems = { glassParts: null };

        const { wrapper, apiPromise } = setupMocks({
            mountOptionsMockData: {
                router: {
                    navigate: jest.fn(),
                    navigateWithSaving: jest.fn(),
                    navigateWithoutSaving: jest.fn(),
                },
                route: {
                    query: {
                        fmgPage: "vehicle-parts",
                    },
                },
                store: {
                    getters: store.getters,
                },
            },
        });

        //Act
        vehicleParts.beforeRouteEnter.call(
            wrapper.vm,
            { query: { fmgPage: "vehicle-parts" } },
            undefined,
            (c) => c(wrapper.vm)
        );
        wrapper.vm.setCmsContent = jest.fn();

        //Assert
        apiPromise.finally(() => {
            expect(wrapper.vm.setCmsContent).toHaveBeenCalled();
            done();
        });
    });

    test("PageData / isRepair populated in Vuex. arePagePrerequisitesValid should be true ", async () => {
        //Arrange
        store.getters.pageData.mockReturnValue(basePartResponse);
        store.getters.lineItems = { glassParts: null };

        const { wrapper } = setupMocks({
            mountOptionsMockData: {
                router: {
                    navigate: jest.fn(),
                    navigateWithSaving: jest.fn(),
                    navigateWithoutSaving: jest.fn(),
                },
                route: {
                    query: {
                        fmgPage: "vehicle-parts",
                    },
                },
                store: {
                    getters: store.getters,
                },
            },
        });

        //Act
        vehicleParts.beforeRouteEnter.call(
            wrapper.vm,
            { query: { fmgPage: "vehicle-parts" } },
            undefined,
            (c) => c(wrapper.vm)
        );

        let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();
        await nextTick();

        //Assert
        expect(arePagePrerequisitesValid).toBe(true);
    });

    test("Initial data, should populate this.selectedGlassParts", async () => {
        //Arrange
        store.getters.pageData.mockReturnValue(basePartResponse);
        store.getters.lineItems = { glassParts: [{ partNumber: "DB12209YPYNOEM" }] };

        const { wrapper } = setupMocks({
            mountOptionsMockData: {
                router: {
                    navigate: jest.fn(),
                    navigateWithSaving: jest.fn(),
                    navigateWithoutSaving: jest.fn(),
                },
                route: {
                    query: {
                        fmgPage: "vehicle-parts",
                    },
                },
                store: {
                    getters: store.getters,
                },
            },
        });

        //Act
        vehicleParts.beforeRouteEnter.call(
            wrapper.vm,
            { query: { fmgPage: "vehicle-parts" } },
            undefined,
            (c) => c(wrapper.vm)
        );

        await nextTick();

        //Assert
        expect(wrapper.vm.selectedGlassParts).toEqual({
            "Rear-Stationary": {
                partNumber: "DB12209YPYNOEM",
                description: "heated glass, solar, 1 hole",
                color: "Gray Tint Privacy",
                requiresRecalibration: false,
                requiresCapabilityQuestions: false,
                childParts: null,
            },
        });
    });

    test("User had part questions > navigateBack triggers a router.navigateWithoutSaving change with correct scenario", async () => {
        //Arrange
        const { wrapper } = setupMocks({
            mountOptionsMockData: {
                router: {
                    navigate: jest.fn(),
                    navigate: jest.fn(),
                    navigateWithSaving: jest.fn(),
                    navigateWithoutSaving: jest.fn(),
                },
                route: {
                    query: {
                        fmgPage: "vehicle-parts",
                    },
                },
                store: {
                    getters: {
                        pageData: () => {
                            return {
                                partsOrQuestions: [
                                    {
                                        glassName: "Stationary",
                                        glassLocation: "Rear",
                                        parts: null,
                                        partQuestions: [
                                            {
                                                testProperty: "some value",
                                            },
                                        ],
                                    },
                                ],
                            };
                        },
                        lineItems: {
                            glassParts: null,
                        },
                        vehicle: {
                            vin: "MY_VIN",
                        },
                    },
                },
            },
        });

        //Act
        vehicleParts.beforeRouteEnter.call(
            wrapper.vm,
            { query: { fmgPage: "vehicle-parts" } },
            undefined,
            (c) => c(wrapper.vm)
        );

        store.dispatch = jest.fn(() => {});

        await wrapper.vm.navigateBack();

        //Assert
        expect(wrapper.vm.$router.navigateWithoutSaving).toHaveBeenCalledWith(
            navigationScenarios.CLICKED_BACK_WITH_PART_QUESTIONS,
            wrapper.vm.$route
        );
    });

    test("User did not have part questions > navigateBack triggers a router.navigateWithoutSaving change with correct scenario", async () => {
        //Arrange
        const { wrapper } = setupMocks({
            mountOptionsMockData: {
                router: {
                    navigate: jest.fn(),
                    navigate: jest.fn(),
                    navigateWithSaving: jest.fn(),
                    navigateWithoutSaving: jest.fn(),
                },
                route: {
                    query: {
                        fmgPage: "vehicle-parts",
                    },
                },
                store: {
                    getters: {
                        pageData: () => basePartResponse,
                        lineItems: {
                            glassParts: null,
                        },
                        vehicle: {
                            vin: "MY_VIN",
                        },
                    },
                },
            },
        });

        //Act
        vehicleParts.beforeRouteEnter.call(
            wrapper.vm,
            { query: { fmgPage: "vehicle-parts" } },
            undefined,
            (c) => c(wrapper.vm)
        );

        store.dispatch = jest.fn(() => {});
        await wrapper.vm.navigateBack();

        //Assert
        expect(wrapper.vm.$router.navigateWithoutSaving).toHaveBeenCalledWith(
            navigationScenarios.CLICKED_BACK_WITH_VIN_AND_NO_MORE_QUESTIONS,
            wrapper.vm.$route
        );
    });

    test("ForwardButtonAction triggers a router.navigateWithSaving change if there are child part questions", async () => {
        //Arrange
        store.getters.pageData.mockReturnValueOnce({
            partsOrQuestions: [
                {
                    glassName: "Single",
                    glassLocation: "Windshield",
                    parts: [
                        {
                            partNumber: "FW03861GTYN",
                            description:
                                "rain sensor, heated glass, auto dimming mirror, solar, 3rd visor band, condensation sensor",
                            color: "Green Tint",
                            requiresRecalibration: false,
                            requiresCapabilityQuestions: false,
                            recalibrationType: null,
                            childParts: null,
                            childPartQuestions: [
                                {
                                    questionSequence: 1,
                                    questionText:
                                        "Does the rubber seal around your windshield have a chrome strip running through it?",
                                    answers: [
                                        {
                                            answerResult: "WKT D1106 C",
                                            answerText: "Yes",
                                            nextQuestionSequence: null,
                                        },
                                        {
                                            answerResult: "WKT D1106 B",
                                            answerText: "No",
                                            nextQuestionSequence: null,
                                        },
                                    ],
                                },
                            ],
                        },
                    ],
                    partQuestions: null,
                },
            ],
        });
        store.getters.lineItems = { glassParts: {} };

        const { wrapper } = setupMocks({
            mountOptionsMockData: {
                router: {
                    navigate: jest.fn(),
                    navigateWithSaving: jest.fn(),
                    navigateWithoutSaving: jest.fn(),
                },
                route: {
                    query: {
                        fmgPage: "vehicle-parts",
                    },
                },
                store: {
                    getters: store.getters,
                    commit: store.commit,
                },
            },
        });

        wrapper.setData({
            selectedGlassParts: { "Rear-Stationary": { partNumber: "FW03861GTYN" } },
        });

        //Act
        vehicleParts.beforeRouteEnter.call(
            wrapper.vm,
            { query: { fmgPage: "vehicle-parts" } },
            undefined,
            (c) => c(wrapper.vm)
        );

        await wrapper.vm.forwardButtonAction();

        //Assert
        expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalled();
    });

    test("ForwardButtonAction triggers a router.navigateWithSaving change if there are capability questions", async () => {
        //Arrange
        store.getters.pageData.mockReturnValueOnce({
            partsOrQuestions: [
                {
                    glassName: "Single",
                    glassLocation: "Windshield",
                    parts: [
                        {
                            partNumber: "DB12209GTYN",
                            description: "heated glass, solar, 1 hole",
                            color: "Green Tint",
                            requiresRecalibration: false,
                            requiresCapabilityQuestions: true,
                            childParts: null,
                        },
                    ],
                    partQuestions: null,
                },
            ],
        });
        store.getters.lineItems = { glassParts: {} };
        store.getters.vehicle = { carId: "TEST_CAR_ID" };

        const { wrapper } = setupMocks({
            mountOptionsMockData: {
                router: {
                    navigate: jest.fn(),
                    navigateWithSaving: jest.fn(),
                    navigateWithoutSaving: jest.fn(),
                },
                route: {
                    query: {
                        fmgPage: "vehicle-parts",
                    },
                },
                store: {
                    getters: store.getters,
                    commit: store.commit,
                },
                actionList: [
                    {
                        actionName: storeActions.GET_CAPABILITY_QUESTIONS,
                        data: [],
                    },
                ],
            },
        });

        wrapper.setData({
            selectedGlassParts: { "Rear-Stationary": { partNumber: "DB12209GTYN" } },
        });

        //Act
        vehicleParts.beforeRouteEnter.call(
            wrapper.vm,
            { query: { fmgPage: "vehicle-parts" } },
            undefined,
            (c) => c(wrapper.vm)
        );

        await wrapper.vm.forwardButtonAction();

        //Assert
        expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalled();
    });

    test("ForwardButtonAction saves selected parts to store if no molding or capability questions", async () => {
        //Arrange
        store.getters.pageData.mockReturnValueOnce(basePartResponse);
        store.getters.lineItems = { glassParts: {} };
        store.getters.vehicle = { carId: "TEST_CAR_ID" };
        store.getters.payment = { insuranceCoverage: {} };
        store.getters.order = {};

        const { wrapper } = setupMocks({
            mountOptionsMockData: {
                router: {
                    navigate: jest.fn(),
                    navigateWithSaving: jest.fn(),
                    navigateWithoutSaving: jest.fn(),
                },
                route: {
                    query: {
                        fmgPage: "vehicle-parts",
                    },
                },
                store: {
                    getters: store.getters,
                    commit: store.commit,
                },
            },
        });

        wrapper.vm.dispatchStoreAction = jest.fn();

        wrapper.setData({
            selectedGlassParts: { "Rear-Stationary": { partNumber: "DB12209GTYN" } },
        });

        //Act
        vehicleParts.beforeRouteEnter.call(
            wrapper.vm,
            { query: { fmgPage: "vehicle-parts" } },
            undefined,
            (c) => c(wrapper.vm)
        );

        await wrapper.vm.forwardButtonAction();

        //Assert
        expect(wrapper.vm.dispatchStoreAction).toHaveBeenCalled();

        // TODO KO UNCOMMENT FOR QUOTE PAGES RELEASE
        // expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledWith(
        //     navigationScenarios.CLICKED_FORWARD_WITH_NO_MORE_QUESTIONS,
        //     { query: { fmgPage: "vehicle-parts" } }
        // );
    });
});

function setupMocks({ pageHeaderWidgetHeaderText = {}, mountOptionsMockData = {} }) {
    //Mock api responses
    const apiResponses = {
        cmsContent: {
            FunnelSubHeaderWidget: pageHeaderWidgetHeaderText,
            VehicleBannerWidget: {
                GenericVehicleImage:
                    "https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/blurred-image.jpg?sfvrsn=a6ce3034_3",
            },
            FunnelHeaderWidget: {
                LogoImage:
                    "https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/safelite-logo.svg?sfvrsn=45e7ed06_3",
            },
            ColorQuestionWidget: "Please choose your rear window tint color",
            FeatureQuestionWidget: "Ok no choose features",
            AlertWidget: {
                BodyText: "Please choose your tint color",
                HeadlineText: "Just a few more steps to go",
            },
        },
    };

    const apiPromise = Promise.resolve(apiResponses);

    settleAllPromises.mockImplementation(() => apiPromise);
    fetchCmsContentForPage.mockImplementation(() => Promise.resolve());

    const mountOptions = getMountOptions(mountOptionsMockData);
    const wrapper = shallowMount(vehicleParts, mountOptions);

    const partQuestionRearWrapper = wrapper.findComponent({ name: "glassPartQuestion" });
    partQuestionRearWrapper.vm.initializeComponent = glassPartQuestion.methods.initializeComponent;

    wrapper.vm.setCmsContent = baseMixin.methods.setCmsContent;
    wrapper.vm.$refs.navbar.removeLoader = jest.fn();
    wrapper.vm.$refs.loadingModal.showModal = jest.fn();
    // wrapper.vm.$refs.onSubmit = jest.fn();
    // wrapper.vm.$refs.onInvalidSubmit = jest.fn();

    return { wrapper, apiPromise };
}
