import { shallowMount, flushPromises } from "@vue/test-utils";
import { getMountOptions } from "@/helpers/unit-test-helper.js";
import { applicationConfig } from "@/constants/application-config";
import { storeActions } from "@/constants/store-actions";
import quote from "@/layouts/quote/quote.vue";
import store from "@/store";
import * as navigateToHeritage from "@/helpers/heritage-integration/navigation-helper";
import { nextTick } from "vue";
import { experimentSettings } from "@/constants/experiments";
import experimentMixin from "@/mixins/experiment-mixin.js";
import baseMixin from "@/mixins/base-mixin.js";
import { containsLineItemWithPartType } from "../../helpers/service-package-helper";

jest.mock("@/store", () => ({
    commit: jest.fn(),
    dispatch: jest.fn(),
}));

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

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

jest.mock("@/helpers/promotions-helper", () => ({
    revalidatePromosAndValidateQueryStringPromo: jest.fn(() => {
        return { validatePromoResponse: null, revalidatePromoResponse: null };
    }),
}));

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

// START beforeRouteEnter mock arranging //
jest.mock("@/mixins/base-mixin", () => ({
    methods: {
        dispatchStoreAction(action, items, encode) {
            if (action === mockPriceOrderStoreAction) return items;
            else return mockStoreActionResults[action];
        },
        dispatchStoreActionWithLogging(action, items, pageName, encode) {
            if (action === mockPriceOrderStoreAction) return items;
            else return mockStoreActionResults[action];
        },
        getTierOnePackagePrice() {
            return mockTierOnePrice;
        },
        filterOutFees(items) {
            return null;
        },
        filterOutServicePackageDiscountPart(items) {
            return null;
        },
        isFormValid(form) {
            return true;
        },
    },
}));

const mockExperimentSettings = experimentSettings;

jest.mock("@/mixins/experiment-mixin.js", () => ({
    methods: {
        getSettingValue(settingName) {
            if (settingName === mockExperimentSettings.SERVICE_PACKAGE_DISCOUNT) {
                return true;
            }
            if (
                settingName === mockExperimentSettings.INSURANCE_TAB_TO_DISPLAY_THRESHOLD_INTERNAL
            ) {
                return 300;
            } else if (
                settingName === mockExperimentSettings.INSURANCE_TAB_TO_DISPLAY_THRESHOLD_EXTERNAL
            ) {
                return 500;
            }
            return "test";
        },
        hasSettingEqualTo(settingName) {
            if (settingName === mockExperimentSettings.DISPLAY_AFTERPAY_BREAKOUT_DISPLAY) {
                return false;
            }
            return "test";
        },
    },
}));

const mockMixin = {
    methods: {
        filterOutFees: jest.fn().mockImplementation(() => {
            return null;
        }),
        isFormValid: jest.fn().mockImplementation(() => {
            return true;
        }),
    },
};
let mockTierOnePrice = 501;

const mockPriceOrderStoreAction = storeActions.PRICE_ORDER_ITEMS_AND_SAVE_SERVER_DATA;
const mockStoreActionResults = {};

mockStoreActionResults[storeActions.GET_WIPERS] = Promise.resolve([
    { partNumber: "SBB24", partType: "FRONT WIPER" },
]);
mockStoreActionResults[storeActions.GET_RAIN_DEFENSE] = Promise.resolve({
    partNumber: "RAIN DEFENSE",
    partType: "RAIN DEFENSE",
});
mockStoreActionResults[storeActions.GET_SUPPORTING_ITEMS] = Promise.resolve([
    { partNumber: "WSREPAIR", partType: "WSREPAIR" },
]);
// END beforeRouteEnter mock arranging

store.getters = {
    order: {
        payment: {
            insuranceCoverage: {},
            isInsurance: false,
            parentAccountNumber: applicationConfig.CASH_PARENT_ACCOUNT_NUMBER,
        },
        customer: {
            emailAddress: "test@test.com",
        },
    },
};

afterEach(() => {
    // reset store after each test
    store.getters = {
        order: {
            payment: {
                parentAccountNumber: applicationConfig.CASH_PARENT_ACCOUNT_NUMBER,
            },
        },
        payment: {
            insuranceCoverage: {},
            isInsurance: false,
        },
        customer: {
            emailAddress: "test@test.com",
        },
    };
});

describe("quote.vue", () => {
    test("IsInsurance false should navigateWithSaving", async () => {
        //Arrange
        store.getters.payment = {
            insuranceCoverage: {},
            isInsurance: false,
        };
        store.getters.order = {
            lineItems: [],
            payment: {
                parentAccountNumber: 167132,
            },
        };
        const { wrapper } = setupMocks({
            customMountOptions: {
                router: {
                    navigateWithSaving: jest.fn(),
                },
                route: { quote },
            },
        });

        wrapper.vm.dispatchStoreAction = jest.fn(() => {
            return {
                data: [],
            };
        });

        //Act
        await wrapper.vm.forwardButtonAction();

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

    test("should pass arePagePrerequisitesValid with a repair order", () => {
        //Arrange
        store.getters = {
            order: {
                lineItems: [],
                serviceLocation: {
                    zipCode: "12345",
                    zipCodeCtu: "value",
                },
                damage: {
                    isRepair: true,
                },
                payment: {
                    insuranceCoverage: {
                        isVerified: false,
                    },
                },
                referralNumber: "1234567",
            },
        };
        const { wrapper } = setupMocks({});

        let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();

        expect(arePagePrerequisitesValid).toBe(true);
    });
    test("should pass arePagePrerequisitesValid with a replace order", () => {
        //Arrange
        store.getters = {
            order: {
                serviceLocation: {
                    zipCode: "12345",
                    zipCodeCtu: "value",
                },
                damage: {
                    isRepair: false,
                },
                referralNumber: "1234567",
                lineItems: {
                    glassParts: ["item", "item2"],
                },
                payment: {
                    insuranceCoverage: {
                        isVerified: false,
                    },
                },
            },
        };
        const { wrapper } = setupMocks({});

        let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();

        expect(arePagePrerequisitesValid).toBe(true);
    });
    test("should fail arePagePrerequisitesValid without glass parts or flagged as repair", () => {
        //Arrange
        store.getters = {
            order: {
                lineItems: [],
                serviceLocation: {
                    zipCode: "12345",
                    zipCodeCtu: "value",
                },
                damage: {
                    isRepair: false,
                },
                referralNumber: "1234567",
            },
        };
        const { wrapper } = setupMocks({});

        let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();

        expect(arePagePrerequisitesValid).toBe(false);
    });
    test("should have non-null values for necessary data members after 'beforeRouteEnter'", async () => {
        //Arrange
        store.getters = {
            lineItems: {
                glassParts: ["item", "item2"],
            },
            pageData: jest.fn((page) => {
                if (page === "quote") {
                    return { saveProgressPopupSkipped: true };
                }
                return {};
            }),
            applicationUser: {
                experiments: [],
            },
            order: {
                lineItems: {
                    glassParts: ["item", "item2"],
                },
                payment: {},
                customer: {
                    emailAddress: "test@test.com",
                },
                serviceLocation: {
                    zipCode: "12345",
                    zipCodeCtu: "value",
                },
            },
            vehicle: {
                cardId: "123",
            },
            experimentSettings: {
                settingName: "SERVICE_PACKAGE_DISCOUNT",
            },
        };
        const { wrapper } = setupMocks({});

        //mock this to avoid needing to populate this.$route in an unrelated test
        wrapper.vm.getDefaultIsInsuranceSelectedValue = jest.fn();

        //Act
        await quote.beforeRouteEnter.call(
            wrapper.vm,
            { query: { fmgPage: "quote" } },
            undefined,
            (c) => c(wrapper.vm)
        );

        //Assert
        expect(wrapper.vm.lineItems !== null).toBe(true);
        expect(wrapper.vm.availableVaps !== null).toBe(true);
        expect(wrapper.vm.availableLineItems !== null).toBe(true);
        // This should have its own test
        //expect(vm.isInsuranceSelected !== null).toBe(true);
    });
    test("Returns true if service package discount setting is true", async () => {
        //Arrange
        store.getters = {
            lineItems: {
                glassParts: ["item", "item2"],
            },
            pageData: jest.fn((page) => {
                if (page === "quote") {
                    return { saveProgressPopupSkipped: true };
                }
                return {};
            }),
            applicationUser: {
                experiments: [],
            },
            order: {
                lineItems: {
                    glassParts: ["item", "item2"],
                },
                payment: {},
                customer: {
                    emailAddress: "test@test.com",
                },
                serviceLocation: {
                    zipCode: "12345",
                    zipCodeCtu: "value",
                },
            },
            vehicle: {
                cardId: "123",
            },
            experimentSettings: {
                settingName: "SERVICE_PACKAGE_DISCOUNT",
            },
        };
        const { wrapper } = setupMocks({});

        wrapper.vm.$route = { query: { isInsurance: "false" } };

        const isServicePackageDiscount = experimentMixin.methods.getSettingValue(
            experimentSettings.SERVICE_PACKAGE_DISCOUNT
        );

        //Act
        await quote.beforeRouteEnter.call(
            wrapper.vm,
            { query: { fmgPage: "quote" } },
            undefined,
            (c) => c(wrapper.vm)
        );
        //Assert
        expect(isServicePackageDiscount).toBe(true);
    });
    test("should default to insurance if query param 'isInsurance' is true", async () => {
        //Arrange
        store.getters = {
            lineItems: {
                glassParts: ["item", "item2"],
            },
            pageData: jest.fn((page) => {
                if (page === "quote") {
                    return { saveProgressPopupSkipped: true };
                }
                return {};
            }),
            applicationUser: {
                experiments: [],
            },
            order: {
                lineItems: {
                    glassParts: ["item", "item2"],
                },
                payment: {
                    isInsurance: null,
                },
                customer: {
                    emailAddress: "test@test.com",
                },
                serviceLocation: {
                    state: null,
                },
            },
            vehicle: {
                cardId: "123",
            },
            experimentSettings: {
                settingName: "SERVICE_PACKAGE_DISCOUNT",
            },
        };
        const { wrapper } = setupMocks({});
        wrapper.vm.$route = { query: { isInsurance: "true" } };

        //Act
        await quote.beforeRouteEnter.call(
            wrapper.vm,
            { query: { fmgPage: "quote" } },
            undefined,
            (c) => c(wrapper.vm)
        );

        //Assert
        expect(wrapper.vm.isInsuranceSelected).toBe(true);
    });
    test("should use amount threshold if query param 'isInsurance' is false", async () => {
        //Arrange
        store.getters = {
            lineItems: {
                glassParts: ["item", "item2"],
            },
            pageData: jest.fn((page) => {
                if (page === "quote") {
                    return { saveProgressPopupSkipped: true };
                }
                return {};
            }),
            applicationUser: {
                experiments: [],
            },
            order: {
                lineItems: {
                    glassParts: ["item", "item2"],
                },
                payment: {
                    isInsurance: null,
                },
                customer: {
                    emailAddress: "test@test.com",
                },
                serviceLocation: {
                    state: null,
                },
            },
            vehicle: {
                cardId: "123",
            },
            experimentSettings: {
                settingName: "SERVICE_PACKAGE_DISCOUNT",
            },
        };
        mockTierOnePrice = 200;
        const { wrapper } = setupMocks({});

        //Act
        await quote.beforeRouteEnter.call(
            wrapper.vm,
            { query: { fmgPage: "quote", isInsurance: false } },
            undefined,
            (c) => c(wrapper.vm)
        );

        //Assert
        expect(wrapper.vm.isInsuranceSelected).toBe(false);
    });
    test("should default to insurance if insurance selection is saved to store", async () => {
        //Arrange

        store.getters = {
            lineItems: {
                glassParts: ["item", "item2"],
            },
            pageData: jest.fn((page) => {
                if (page === "quote") {
                    return { saveProgressPopupSkipped: true };
                }
                return {};
            }),
            applicationUser: {
                experiments: [],
            },
            order: {
                lineItems: {
                    glassParts: ["item", "item2"],
                },
                payment: {
                    isInsurance: true,
                },
                customer: {
                    emailAddress: "test@test.com",
                },
                serviceLocation: {
                    state: null,
                },
            },
            vehicle: {
                cardId: "123",
            },
            experimentSettings: {
                settingName: "SERVICE_PACKAGE_DISCOUNT",
            },
        };
        const { wrapper } = setupMocks({});
        // Ensure that query param isn't overriding selection
        wrapper.vm.$route = { query: null };

        //Act
        await quote.beforeRouteEnter.call(
            wrapper.vm,
            { query: { fmgPage: "quote" } },
            undefined,
            (c) => c(wrapper.vm)
        );

        //Assert
        expect(wrapper.vm.isInsuranceSelected).toBe(true);
    });
    test("should default to cash if cash selection is saved to store", async () => {
        //Arrange
        store.getters = {
            lineItems: {
                glassParts: ["item", "item2"],
            },
            pageData: jest.fn((page) => {
                if (page === "quote") {
                    return { saveProgressPopupSkipped: true };
                }
                return {};
            }),
            applicationUser: {
                experiments: [],
            },
            order: {
                lineItems: {
                    glassParts: ["item", "item2"],
                },
                payment: {
                    isInsurance: false,
                },
                customer: {
                    emailAddress: "test@test.com",
                },
                serviceLocation: {
                    state: null,
                },
            },
            vehicle: {
                cardId: "123",
            },
            experimentSettings: {
                settingName: "SERVICE_PACKAGE_DISCOUNT",
            },
        };
        const { wrapper } = setupMocks({});
        // Ensure that query param isn't overriding selection
        wrapper.vm.$route = { query: null };

        //Act
        await quote.beforeRouteEnter.call(
            wrapper.vm,
            { query: { fmgPage: "quote" } },
            undefined,
            (c) => c(wrapper.vm)
        );

        //Assert
        expect(wrapper.vm.isInsuranceSelected).toBe(false);
    });
    test("should default to cash if total economy package price is under $500", async () => {
        // Also needs no query parameter or previous selection in store to be present
        //Arrange
        store.getters = {
            lineItems: {
                glassParts: ["item", "item2"],
            },
            pageData: jest.fn((page) => {
                if (page === "quote") {
                    return { saveProgressPopupSkipped: true };
                }
                return {};
            }),
            applicationUser: {
                experiments: [],
            },
            order: {
                lineItems: {
                    glassParts: ["item", "item2"],
                },
                payment: {
                    isInsurance: null, // Ensure that previous selection isn't overriding selection
                },
                customer: {
                    emailAddress: "test@test.com",
                },
                serviceLocation: {
                    state: null,
                },
            },
            vehicle: {
                cardId: "123",
            },
            experimentSettings: {
                settingName: "SERVICE_PACKAGE_DISCOUNT",
            },
        };
        mockTierOnePrice = 200;
        const { wrapper } = setupMocks({});
        // Ensure that query param isn't overriding selection
        wrapper.vm.$route = { query: null };

        //Act
        await quote.beforeRouteEnter.call(
            wrapper.vm,
            { query: { fmgPage: "quote" } },
            undefined,
            (c) => c(wrapper.vm)
        );

        //Assert
        expect(wrapper.vm.isInsuranceSelected).toBe(false);
    });
    test("should default to cash if isCashSelected is true, despite all other checks pointing to insurance selection", async () => {
        // Also needs no query parameter or previous selection in store to be present
        //Arrange

        store.getters = {
            lineItems: {
                glassParts: ["item", "item2"],
            },
            pageData: jest.fn((page) => {
                if (page === "quote") {
                    return { saveProgressPopupSkipped: true };
                }
                return {};
            }),
            applicationUser: {
                experiments: [],
            },
            order: {
                lineItems: {
                    glassParts: ["item", "item2"],
                },
                payment: {
                    isInsurance: true,
                },
                customer: {
                    emailAddress: "test@test.com",
                },
                serviceLocation: {
                    state: null,
                },
            },
            vehicle: {
                cardId: "123",
            },
            experimentSettings: {
                settingName: "SERVICE_PACKAGE_DISCOUNT",
            },
        };
        mockTierOnePrice = 505;
        const { wrapper } = setupMocks({});

        //Act
        await quote.beforeRouteEnter.call(
            wrapper.vm,
            { query: { fmgPage: "quote", isInsuranceSelected: true, isCashSelected: true } },
            undefined,
            (c) => c(wrapper.vm)
        );

        //Assert
        expect(wrapper.vm.isInsuranceSelected).toBe(false);
    });
    test("should default to insurance if total economy package price is over $500", async () => {
        // Also needs no query parameter or previous selection in store to be present
        //Arrange

        store.getters = {
            lineItems: {
                glassParts: ["item", "item2"],
            },
            pageData: jest.fn((page) => {
                if (page === "quote") {
                    return { saveProgressPopupSkipped: true };
                }
                return {};
            }),
            applicationUser: {
                experiments: [],
            },
            order: {
                lineItems: {
                    glassParts: ["item", "item2"],
                },
                payment: {
                    isInsurance: null, // Ensure that previous selection isn't overriding selection
                },
                customer: {
                    emailAddress: "test@test.com",
                },
                serviceLocation: {
                    state: null,
                },
            },
            vehicle: {
                cardId: "123",
            },
            experimentSettings: {
                settingName: "SERVICE_PACKAGE_DISCOUNT",
            },
        };
        mockTierOnePrice = 505;
        const { wrapper } = setupMocks({});
        // Ensure that query param isn't overriding selection
        wrapper.vm.$route = { query: null };

        //Act
        await quote.beforeRouteEnter.call(
            wrapper.vm,
            { query: { fmgPage: "quote" } },
            undefined,
            (c) => c(wrapper.vm)
        );

        //Assert
        expect(wrapper.vm.isInsuranceSelected).toBe(true);
    });
    test("Should default to insurance if user Service zip is from certain States", async () => {
        //Arrange

        store.getters = {
            lineItems: {
                glassParts: ["item", "item2"],
            },
            pageData: jest.fn((page) => {
                if (page === "quote") {
                    return { saveProgressPopupSkipped: true };
                }
                return {};
            }),
            applicationUser: {
                experiments: [],
            },
            order: {
                lineItems: {
                    glassParts: ["item", "item2"],
                },
                payment: {
                    isInsurance: null,
                },
                customer: {
                    emailAddress: "test@test.com",
                },
                serviceLocation: {
                    state: "AZ",
                },
            },
            vehicle: {
                cardId: "123",
            },
            experimentSettings: {
                settingName: "SERVICE_PACKAGE_DISCOUNT",
            },
        };
        const { wrapper } = setupMocks({});
        wrapper.vm.$route = { query: null };
        //Act
        await quote.beforeRouteEnter.call(
            wrapper.vm,
            { query: { fmgPage: "quote" } },
            undefined,
            (c) => c(wrapper.vm)
        );
        //Assert
        expect(wrapper.vm.isInsuranceSelected).toBe(true);
    });
    test("On forward button action save promos", async () => {
        //Arrange
        store.getters.payment = {
            insuranceCoverage: {},
            isInsurance: false,
        };
        store.getters.order = {
            lineItems: [],
            payment: {
                parentAccountNumber: 167132,
            },
        };
        const { wrapper } = setupMocks({
            customMountOptions: {
                router: {
                    navigateWithSaving: jest.fn(),
                },
                route: { quote },
            },
        });

        wrapper.vm.forwardButtonAction();

        expect(wrapper.vm.lineItems.promos !== null).toBe(true);
    });
    test("On forward button action save supporting lineItems", async () => {
        //Arrange
        store.getters.payment = {
            insuranceCoverage: {},
            isInsurance: false,
        };
        store.getters.order = {
            lineItems: [],
            payment: {
                parentAccountNumber: 167132,
            },
        };
        const { wrapper } = setupMocks({
            customMountOptions: {
                router: {
                    navigateWithSaving: jest.fn(),
                },
                route: { quote },
            },
        });

        wrapper.vm.forwardButtonAction();

        expect(wrapper.vm.dispatchStoreAction).toHaveBeenCalledWith(
            "saveSupportingItems",
            wrapper.vm.lineItems.supportingItems,
            false
        );
    });
});
describe("quote.vue", () => {
    test("should call forwardButtonAction if isExternalParameter and Insurance is true and form is valid", async () => {
        // Set up the store with isExternalParameter as true

        store.getters = {
            lineItems: {
                glassParts: ["item", "item2"],
            },
            pageData: jest.fn((page) => {
                if (page === "quote") {
                    return { saveProgressPopupSkipped: true };
                }
                return {};
            }),
            applicationUser: {
                experiments: [],
            },
            order: {
                lineItems: {
                    glassParts: ["item", "item2"],
                },
                serviceLocation: {
                    zipCode: "12345",
                    zipCodeCtu: "value",
                },
                damage: {
                    isRepair: false,
                },
                referralNumber: "1234567",
                payment: {
                    isInsurance: true,
                    inactivePromos: [],
                },
                customer: {
                    emailAddress: "test@test.com",
                },
            },
            externalParameterState: { isExternalParameter: 1 },
            externalParameterQuote: {
                isInsurance: true,
                servicePackage: "glassonly",
            },
            payment: {
                isInsurance: true,
                inactivePromos: [],
            },
            vehicle: {
                cardId: "123",
            },
            experimentSettings: {
                settingName: "SERVICE_PACKAGE_DISCOUNT",
            },
        };

        // Set up the component
        const { wrapper } = setupMocks({});
        wrapper.vm.$route = { query: null };
        wrapper.vm.forwardButtonAction = jest.fn();
        const nextFunction = jest.fn((c) => {
            c(wrapper.vm);
        });

        // Call the method that contains the if-else logic
        await quote.beforeRouteEnter.call(
            wrapper.vm,
            { query: { fmgPage: "quote" } },
            undefined,
            nextFunction
        );
        await nextTick();
        await nextTick();
        expect(nextFunction).toHaveBeenCalled();
        expect(baseMixin.methods.isFormValid).toHaveBeenCalled();
        expect(baseMixin.methods.isFormValid()).toBe(true);
        await wrapper.vm.$nextTick();
        expect(wrapper.vm.forwardButtonAction).toHaveBeenCalled();
    });
});

function setupMocks({ customMountOptions }) {
    const mountOptions = getMountOptions({
        ...customMountOptions,
    });

    mountOptions.mixins = [
        {
            methods: {
                getSettingValue: jest.fn(),
            },
        },
    ];

    baseMixin.methods.ResetExternalParamsAndHideModal = jest.fn();
    baseMixin.methods.isFormValid = jest.fn().mockReturnValue(true);
    mountOptions.global.mocks["$store"] = store;
    mountOptions["attachTo"] = document.body;

    const wrapper = shallowMount(quote, mountOptions);
    wrapper.vm.setCmsContent = jest.fn();
    return { wrapper };
}
