import mobileLocationModalQuestions from "./mobile-location-modal-questions";
import { mount, shallowMount } from "@vue/test-utils";
import { storeActions } from "@/constants/store-actions";
import { getMountOptions } from "@/helpers/unit-test-helper.js";
import { getBillToAccountNumber } from "../helpers/service-location-helper/service-location-helper";

const linkWidgetName = "linkWidgetName";
const modalWidgetName = "modalWidgetName";
const mobileFeeDisclaimerWidgetName = "MobileFeeDisclaimerWidget";

const mockLinkCmsContent = {
    BodyText: "Sample link body text here.",
};

const mockModalCmsContent = {
    FooterText: "Sample modal footer text here.",
};

const mockMobileFeeDisclaimerContent = {
    Text: "Sample mobile fee disclaimer text {custom:mobileFee}",
};

const mockMixin = {
    methods: {
        getCmsContent: jest.fn((widgetName, cmsFieldName) => {
            if (widgetName === linkWidgetName) {
                return mockLinkCmsContent[cmsFieldName];
            }

            if (widgetName === modalWidgetName) {
                return mockModalCmsContent[cmsFieldName];
            }

            if (widgetName === mobileFeeDisclaimerWidgetName) {
                return mockMobileFeeDisclaimerContent[cmsFieldName];
            }

            return null;
        }),

        getZipCodeData: jest.fn((zip) => {
            if (zip === "43235" || zip === "55555") {
                return Promise.resolve({
                    containsMilitaryBase: false,
                    isServiceable: true,
                    isValid: true,
                    state: "OH",
                    zipCodeCtu: "01820",
                });
            }

            return Promise.resolve({
                containsMilitaryBase: false,
                isServiceable: false,
                isValid: false,
                state: null,
                zipCodeCtu: null,
            });
        }),

        dispatchStoreAction: jest.fn((actionName) => {
            if (actionName === storeActions.GET_MOBILE_FEE_PART) {
                return Promise.resolve({
                    data: {
                        partNumber: "MOBILE FEE",
                        description: "MOBILE FEE",
                        partType: "FEE",
                    },
                });
            }

            if (actionName === storeActions.PRICE_ORDER_ITEMS_AND_SAVE_SERVER_DATA) {
                return Promise.resolve([
                    {
                        partNumber: "MOBILE FEE",
                        description: "MOBILE FEE",
                        partType: "FEE",
                        laborAmount: 49.99,
                        sellingPrice: 0,
                        kitPrice: 0,
                    },
                ]);
            }
        }),

        getTotalLineItemPrice: jest.fn((lineItem) => {
            return 49.99;
        }),
    },
};

const mockGetPricedMobileFeePart = (mockServiceZipCode) => {
    let mobileFeePart = {};

    if (mockServiceZipCode === "43235") {
        mobileFeePart = {
            partNumber: "MOBILE FEE",
            description: "MOBILE FEE",
            partType: "FEE",
            laborAmount: 49.99,
            sellingPrice: 0,
            kitPrice: 0,
        };
    }

    return Promise.resolve(mobileFeePart);
};

const mockGetPricedRecycleFeePart = (mockServiceZipCode) => {
    let recycleFeePart = {};

    if (mockServiceZipCode === "43235") {
        recycleFeePart = {
            partNumber: "RECYCLE FEE",
            description: "RECYCLE FEE",
            partType: "FEE",
            laborAmount: 39.99,
            sellingPrice: 0,
            kitPrice: 0,
        };
    }

    return Promise.resolve(recycleFeePart);
};

const mockGetServiceabilityDetails = (mockServiceZipCode) => {
    const serviceabilityDetails = {
        isGlassServiceableInshop: true,
        isRecalibrationServiceableInshop: true,
        isGlassServiceableMobile: true,
        isRecalibrationServiceableMobile: true,
    };

    return Promise.resolve(serviceabilityDetails);
};

jest.mock(
    "@/layouts/service-location/helpers/service-location-helper/service-location-helper",
    () => ({
        getPricedMobileFeePart: jest.fn((mockServiceZipCode) => {
            return mockGetPricedMobileFeePart(mockServiceZipCode);
        }),
        getPricedRecycleFeePart: jest.fn((mockServiceZipCode) => {
            return mockGetPricedRecycleFeePart(mockServiceZipCode);
        }),
        getServiceabilityDetails: jest.fn((mockServiceZipCode) => {
            return mockGetServiceabilityDetails(mockServiceZipCode);
        }),
        getBillToAccountNumber: jest.fn(() => {
            return "87291";
        }),
    })
);

describe("mobile-location-modal-questions.vue", () => {
    it("Should copy the modelValue to the internalModel when the component is mounted", async () => {
        // Arrange
        const mobileLocationQuestions = {
            addressQuestions: {
                streetAddress: "555 Some St",
                apartmentNumberOrBusinessName: "Apt 1",
                city: "Funkytown",
                state: "OH",
                zipCode: "55555",
            },
            isVehicleProtected: true,
            serviceZipCode: "55555",
        };

        const { wrapper } = setupMocks({
            mixins: [mockMixin],
            props: {
                modelValue: mobileLocationQuestions,
            },
            mountOptions: {
                attachTo: document.body,
            },
        });

        // Assert
        expect(wrapper.vm.internalModel.addressQuestions.streetAddress).toEqual("555 Some St");
        expect(wrapper.vm.internalModel.addressQuestions.apartmentNumberOrBusinessName).toEqual(
            "Apt 1"
        );
        expect(wrapper.vm.internalModel.addressQuestions.city).toEqual("Funkytown");
        expect(wrapper.vm.internalModel.addressQuestions.state).toEqual("OH");
        expect(wrapper.vm.internalModel.addressQuestions.zipCode).toEqual("55555");
        expect(wrapper.vm.internalModel.isVehicleProtected).toEqual(true);
        expect(wrapper.vm.internalModel.serviceZipCode).toEqual("55555");
    });

    it("Should open the modal when the 'Enter your service address' link is clicked", async () => {
        // Arrange
        const mobileLocationQuestions = {
            addressQuestions: {
                streetAddress: "555 Some St",
                apartmentNumberOrBusinessName: "Apt 1",
                city: "Funkytown",
                state: "OH",
                zipCode: "55555",
            },
            isVehicleProtected: true,
            serviceZipCode: "55555",
        };

        const { wrapper } = setupMocks({
            mixins: [mockMixin],
            props: {
                modelValue: mobileLocationQuestions,
            },
            mountOptions: {
                attachTo: document.body,
            },
        });

        wrapper.vm.$refs.MobileLocationModalWidget.openModal = jest.fn();
        const mobileLocationLink = wrapper.findComponent({ ref: "mobileLocationLink" });

        // // Act
        await mobileLocationLink.trigger("click-event");

        // // Assert
        expect(wrapper.vm.$refs.MobileLocationModalWidget.openModal).toHaveBeenCalled();
    });

    it("Should emit setMobileLocationAndProceed on setMobileLocation for a valid address and vehicle protection answer", async () => {
        // Arrange
        const mobileLocationQuestions = {
            addressQuestions: {
                streetAddress: "",
                apartmentNumberOrBusinessName: "",
                city: "",
                state: "",
                zipCode: "",
            },
            isVehicleProtected: true,
            serviceZipCode: "",
        };

        const newMobileLocationQuestions = {
            addressQuestions: {
                streetAddress: "555 Some St",
                apartmentNumberOrBusinessName: "Apt 1",
                city: "Funkytown",
                state: "OH",
                zipCode: "55555",
            },
            isVehicleProtected: true,
            serviceZipCode: "55555",
        };

        const wrapper = shallowMount(mobileLocationModalQuestions, {
            mixins: [mockMixin],
            props: {
                modelValue: mobileLocationQuestions,
                linkWidgetName: linkWidgetName,
                modalWidgetName: modalWidgetName,
            },
            attachTo: document.body,
        });
        wrapper.vm.$refs.MobileLocationModalWidget.closeModal = jest.fn();

        // Act
        wrapper.vm.internalModel = newMobileLocationQuestions;

        await wrapper.vm.setMobileLocation();

        // Assert
        expect(wrapper.emitted()["setMobileLocationAndProceed"]).toBeTruthy();
        expect(wrapper.emitted()["setMobileLocationAndProceed"][0][0]).toStrictEqual(
            newMobileLocationQuestions
        );
    });

    it("Should not emit setMobileLocationAndProceed on setMobileLocation for an invalid address zip code", async () => {
        // Arrange
        const mobileLocationQuestions = {
            addressQuestions: {
                streetAddress: "",
                apartmentNumberOrBusinessName: "",
                city: "",
                state: "",
                zipCode: "",
            },
            isVehicleProtected: true,
            serviceZipCode: "",
        };

        const newMobileLocationQuestions = {
            addressQuestions: {
                streetAddress: "555 Some St",
                apartmentNumberOrBusinessName: "Apt 1",
                city: "Funkytown",
                state: "OH",
                zipCode: "61000",
            },
            isVehicleProtected: true,
            serviceZipCode: "61000",
        };

        const wrapper = shallowMount(mobileLocationModalQuestions, {
            mixins: [mockMixin],
            props: {
                modelValue: mobileLocationQuestions,
                linkWidgetName: linkWidgetName,
                modalWidgetName: modalWidgetName,
            },
            attachTo: document.body,
        });
        wrapper.vm.$refs.MobileLocationModalWidget.closeModal = jest.fn();
        wrapper.vm.resetModalButtonStyle = jest.fn();

        // Act
        wrapper.vm.internalModel = newMobileLocationQuestions;
        await wrapper.vm.setMobileLocation();

        // Assert
        expect(wrapper.emitted("setMobileLocationAndProceed")).not.toBeTruthy();
    });

    it("Should display invalid zip alert for invalid address zip inputs", async () => {
        // Arrange
        const mobileLocationQuestions = {
            addressQuestions: {
                streetAddress: "",
                apartmentNumberOrBusinessName: "",
                city: "",
                state: "",
                zipCode: "",
            },
            isVehicleProtected: true,
            serviceZipCode: "",
        };

        const newMobileLocationQuestions = {
            addressQuestions: {
                streetAddress: "555 Some St",
                apartmentNumberOrBusinessName: "Apt 1",
                city: "Funkytown",
                state: "OH",
                zipCode: "11111",
            },
            isVehicleProtected: true,
            serviceZipCode: "11111",
        };

        const wrapper = shallowMount(mobileLocationModalQuestions, {
            mixins: [mockMixin],
            props: {
                modelValue: mobileLocationQuestions,
                linkWidgetName: linkWidgetName,
                modalWidgetName: modalWidgetName,
            },
            attachTo: document.body,
        });

        wrapper.vm.internalModel = newMobileLocationQuestions;
        wrapper.vm.resetModalButtonStyle = jest.fn();

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

        // Assert
        expect(wrapper.vm.displayInvalidZipAlert).toBe(true);
    });
    it("Should display mismatch state and zip alert for non-matching state/zip for mobile address zip inputs", async () => {
        // Arrange
        const mobileLocationQuestions = {
            addressQuestions: {
                streetAddress: "",
                apartmentNumberOrBusinessName: "",
                city: "",
                state: "",
                zipCode: "",
            },
            isVehicleProtected: true,
            serviceZipCode: "",
        };

        const newMobileLocationQuestions = {
            addressQuestions: {
                streetAddress: "555 Some St",
                apartmentNumberOrBusinessName: "Apt 1",
                city: "Funkytown",
                state: "AK",
                zipCode: "55555",
            },
            isVehicleProtected: true,
            serviceZipCode: "55555",
        };

        const wrapper = shallowMount(mobileLocationModalQuestions, {
            mixins: [mockMixin],
            props: {
                modelValue: mobileLocationQuestions,
                linkWidgetName: linkWidgetName,
                modalWidgetName: modalWidgetName,
            },
            attachTo: document.body,
        });

        wrapper.vm.internalModel = newMobileLocationQuestions;
        wrapper.vm.resetModalButtonStyle = jest.fn();

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

        // Assert
        expect(wrapper.vm.displayMismatchStateAndZipAlert).toBe(true);
    });
});

function setupMocks({ mountOptions, mixins, props, isShallowMount = true }) {
    const resultingMountOptions = getMountOptions({
        ...mountOptions,
        mixins,
    });

    if (props) resultingMountOptions.propsData = props;

    const wrapper = isShallowMount
        ? shallowMount(mobileLocationModalQuestions, resultingMountOptions)
        : mount(mobileLocationModalQuestions, resultingMountOptions);

    return { wrapper };
}
