import { mount, shallowMount } from "@vue/test-utils";
import serviceZipModalQuestion from "./service-zip-modal-question";
import { getBillToAccountNumber } from "../helpers/service-location-helper/service-location-helper";

jest.mock("@/digital-components/textbox-question/textbox-question", () => ({
    getCmsContent: jest.fn((widgetName, cmsFieldName) => {
        return widgetName[cmsFieldName];
    }),
}));

jest.mock("@/digital-components/modal/modal", () => ({
    methods: {
        closeModal: jest.fn(),
        resetButtonStyle: jest.fn(),
    },
}));

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((mockServiceZipCodeCtu) => {
            return "87291";
        }),
    })
);

const linkWidgetName = "linkWidgetName";
const modalWidgetName = "modalWidgetName";

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

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

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

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

            return null;
        }),

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

            if (zip === "61606") {
                return {
                    containsMilitaryBase: false,
                    isValid: true,
                    state: "IL",
                    zipCodeCtu: "01526",
                };
            }

            return {
                containsMilitaryBase: false,
                isValid: false,
                state: null,
                zipCodeCtu: null,
            };
        }),
    },
};

describe("service-zip-modal-question.vue", () => {
    it("Initial state on load with no existing location info", async () => {
        let serviceZipCodeQuestion = {
            state: "",
            zipCode: "",
            zipCodeCtu: "",
        };

        // Arrange
        const wrapper = mount(serviceZipModalQuestion, {
            mixins: [mockMixin],
            props: {
                modelValue: serviceZipCodeQuestion,
                linkWidgetName: linkWidgetName,
                modalWidgetName: modalWidgetName,
            },
            attachTo: document.body,
        });

        // Assert
        expect(wrapper.html()).toEqual(expect.stringContaining(mockLinkCmsContent["BodyText"]));
    });

    it("Initial state on load with existing location info", async () => {
        // Arrange
        let serviceZipCodeQuestion = {
            state: "OH",
            zipCode: "43235",
            zipCodeCtu: "01820",
        };

        const wrapper = mount(serviceZipModalQuestion, {
            mixins: [mockMixin],
            props: {
                modelValue: serviceZipCodeQuestion,
                linkWidgetName: linkWidgetName,
                modalWidgetName: modalWidgetName,
            },
            attachTo: document.body,
        });

        // Assert
        expect(wrapper.html()).not.toEqual(expect.stringContaining(mockLinkCmsContent["BodyText"]));
    });

    it("Should emit update:modelValue on setZipCode for a valid, serviceable zip", async () => {
        // Arrange
        let serviceZipCodeQuestion = {
            state: "IL",
            zipCode: "61606",
            zipCodeCtu: "01526",
        };

        const zip = "43235";

        const wrapper = mount(serviceZipModalQuestion, {
            mixins: [mockMixin],
            props: {
                modelValue: serviceZipCodeQuestion,
                mobileFeePart: {},
                linkWidgetName: linkWidgetName,
                modalWidgetName: modalWidgetName,
            },
            attachTo: document.body,
        });

        // Act
        wrapper.vm.internalModel.zipCode = zip;

        await wrapper.vm.setZipCode();

        let expectedEmit = [[{ state: "OH", zipCode: "43235", zipCodeCtu: "01820" }]];

        // Assert
        expect(wrapper.emitted("update:modelValue")).toEqual(expectedEmit);
    });

    it("Should not emit update:modelValue on setZipCode for an invalid zip", async () => {
        // Arrange
        let serviceZipCodeQuestion = {
            state: "IL",
            zipCode: "61606",
            zipCodeCtu: "01526",
        };

        const zip = "";

        const wrapper = mount(serviceZipModalQuestion, {
            mixins: [mockMixin],
            props: {
                modelValue: serviceZipCodeQuestion,
                linkWidgetName: linkWidgetName,
                modalWidgetName: modalWidgetName,
            },
            attachTo: document.body,
        });

        // Act
        wrapper.vm.internalModel.zipCode = zip;
        await wrapper.vm.setZipCode();

        // Assert
        expect(wrapper.emitted("update:modelValue")).not.toBeTruthy();
    });

    it("Should display invalid zip alerts for invalid ip inputs", async () => {
        // Arrange
        let serviceZipCodeQuestion = {
            state: "IL",
            zipCode: "61606",
            zipCodeCtu: "01526",
        };

        const zip = "11111";

        const wrapper = mount(serviceZipModalQuestion, {
            mixins: [mockMixin],
            props: {
                modelValue: serviceZipCodeQuestion,
                linkWidgetName: linkWidgetName,
                modalWidgetName: modalWidgetName,
            },
            attachTo: document.body,
        });

        // Act
        wrapper.vm.internalModel.zipCode = zip;
        await wrapper.vm.setZipCode();

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

    it("Should reset all alerts on onModalClosed", async () => {
        // Arrange
        let serviceZipCodeQuestion = {
            state: "IL",
            zipCode: "61606",
            zipCodeCtu: "01526",
        };

        const zip = "";

        const wrapper = mount(serviceZipModalQuestion, {
            mixins: [mockMixin],
            props: {
                modelValue: serviceZipCodeQuestion,
                linkWidgetName: linkWidgetName,
                modalWidgetName: modalWidgetName,
            },
            attachTo: document.body,
        });

        // Act
        wrapper.vm.internalModel.zipCode = zip;
        await wrapper.vm.setZipCode();
        wrapper.vm.onModalClosed();

        // Assert
        expect(wrapper.vm.displayInvalidZipAlert).toBe(false);
    });

    it("Should prepopulate the zip on onModalOpened", async () => {
        // Arrange
        let serviceZipCodeQuestion = {
            state: "IL",
            zipCode: "61606",
            zipCodeCtu: "01526",
        };

        const zip = "123";

        const wrapper = mount(serviceZipModalQuestion, {
            mixins: [mockMixin],
            props: {
                modelValue: serviceZipCodeQuestion,
                linkWidgetName: linkWidgetName,
                modalWidgetName: modalWidgetName,
            },
            attachTo: document.body,
        });

        // Act
        wrapper.vm.internalModel.zipCode = zip;
        wrapper.vm.onModalOpened();

        // Assert
        expect(wrapper.vm.internalModel.zipCode).toEqual("61606");
    });
});
