import { shallowMount } from "@vue/test-utils";
import { storeActions } from "@/constants/store-actions";
import { getMountOptions } from "@/helpers/unit-test-helper.js";
import shopQuestion from "./shop-question";

jest.mock("@/mixins/base-mixin", () => ({
    methods: {
        dispatchStoreAction(action, items, encode) {
            if (action === mockGetProvidersStoreAction) {
                return new Promise((resolve) => {
                    resolve(mockNewShopList);
                });
            }
        },
        scrollToPageBottom() {},
    },
}));

const mockGetProvidersStoreAction = storeActions.GET_PROVIDERS;
const mockNewShopList = {
    shopProviders: [
        {
            address: {
                city: "COLUMBUS",
                country: "US",
                state: "OH",
                streetAddress: "1670 HARMON AVE",
                zipCode: "43223",
            },
            distanceInMiles: 15.9727889297435,
            providerNumber: "006747",
        },
        {
            address: {
                city: "POWELL",
                country: "US",
                state: "OH",
                streetAddress: "3938 POWELL RD",
                zipCode: "43065",
            },
            distanceInMiles: 16.2690495685233,
            providerNumber: "003341",
        },
        {
            address: {
                city: "Columbus",
                country: "US",
                state: "OH",
                streetAddress: "4580 W Broad St",
                zipCode: "43228",
            },
            distanceInMiles: 19.4618116611001,
            providerNumber: "003342",
        },
    ],
};

const mockCmsContent = {
    QuestionText: "Select a shop:",
};

const cmsWidgetName = "ShopQuestionWidget";
const shopQuestionInitialData = {
    mobileProviderNumber: "001820",
    shopProviders: [
        {
            address: {
                city: "WESTERVILLE",
                country: "US",
                state: "OH",
                streetAddress: "4403 EXECUTIVE PKWY",
                zipCode: "43081",
            },
            distanceInMiles: 5.16769294095201,
            providerNumber: "003335",
        },
        {
            address: {
                city: "WORTHINGTON",
                country: "US",
                state: "OH",
                streetAddress: "760 DEARBORN PARK LN",
                zipCode: "43085",
            },
            distanceInMiles: 10.5865432478478,
            providerNumber: "001820",
        },
        {
            address: {
                city: "COLUMBUS",
                country: "US",
                state: "OH",
                streetAddress: "5015 N HIGH ST",
                zipCode: "43214",
            },
            distanceInMiles: 11.738869544543,
            providerNumber: "003343",
        },
        {
            address: {
                city: "COLUMBUS",
                country: "US",
                state: "OH",
                streetAddress: "1670 HARMON AVE",
                zipCode: "43223",
            },
            distanceInMiles: 15.9727889297435,
            providerNumber: "006747",
        },
        {
            address: {
                city: "POWELL",
                country: "US",
                state: "OH",
                streetAddress: "3938 POWELL RD",
                zipCode: "43065",
            },
            distanceInMiles: 16.2690495685233,
            providerNumber: "003341",
        },
        {
            address: {
                city: "Columbus",
                country: "US",
                state: "OH",
                streetAddress: "4580 W Broad St",
                zipCode: "43228",
            },
            distanceInMiles: 19.4618116611001,
            providerNumber: "003342",
        },
    ],
};

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

            return null;
        }),
    },
};

describe("shop-question.vue", () => {
    beforeEach(() => {
        const container = document.createElement("div");
        container.scrollTo = jest.fn();

        container.classList.add("page-container-grouped-styles");
        document.body.appendChild(container);
    });

    it("Should display first three shops when an appointment type has already been selected", async () => {
        // Arrange
        const { wrapper } = setupMocks({
            mixins: [mockMixin],
            props: {
                modelValue: null,
                serviceZipCode: "43081",
                selectedAppointmentType: "Dropoff",
                cmsWidgetName: cmsWidgetName,
                isDisplayed: true,
                shopProviderData: null,
            },
            mountOptions: {
                attachTo: document.body,
            },
        });

        await wrapper.setProps({
            shopProviderData: shopQuestionInitialData,
        });

        // Act
        await wrapper.vm.$nextTick();
        await wrapper.vm.$nextTick();

        // Assert
        expect(wrapper.vm.answers.length).toEqual(3);
        expect(wrapper.vm.answers).toEqual([
            {
                buttonBodyCopy: "4403 Executive Pkwy, Westerville, OH 43081",
                buttonLabel: "Westerville",
                buttonLabelSubCopy: "5 mi",
                value: "003335",
                additionalButtonData: wrapper.vm.additionalButtonData,
            },
            {
                buttonBodyCopy: "760 Dearborn Park Ln, Worthington, OH 43085",
                buttonLabel: "Worthington",
                buttonLabelSubCopy: "10.5 mi",
                value: "001820",
                additionalButtonData: wrapper.vm.additionalButtonData,
            },
            {
                buttonBodyCopy: "5015 N High St, Columbus, OH 43214",
                buttonLabel: "Columbus",
                buttonLabelSubCopy: "11.5 mi",
                value: "003343",
                additionalButtonData: wrapper.vm.additionalButtonData,
            },
        ]);
    });

    it("Should display the 'Show more locations' link when there are more than three locations to chose from", async () => {
        // Arrange
        const alsoShopQuestionInitialData = {
            shopProviders: [
                {
                    address: {
                        city: "WESTERVILLE",
                        country: "US",
                        state: "OH",
                        streetAddress: "4403 EXECUTIVE PKWY",
                        zipCode: "43081",
                    },
                    distanceInMiles: 5.16769294095201,
                    providerNumber: "003335",
                },
                {
                    address: {
                        city: "WORTHINGTON",
                        country: "US",
                        state: "OH",
                        streetAddress: "760 DEARBORN PARK LN",
                        zipCode: "43085",
                    },
                    distanceInMiles: 10.5865432478478,
                    providerNumber: "001820",
                },
                {
                    address: {
                        city: "COLUMBUS",
                        country: "US",
                        state: "OH",
                        streetAddress: "5015 N HIGH ST",
                        zipCode: "43214",
                    },
                    distanceInMiles: 11.738869544543,
                    providerNumber: "003343",
                },
                {
                    address: {
                        city: "COLUMBUS",
                        country: "US",
                        state: "OH",
                        streetAddress: "1670 HARMON AVE",
                        zipCode: "43223",
                    },
                    distanceInMiles: 15.9727889297435,
                    providerNumber: "006747",
                },
            ],
        };

        const { wrapper } = setupMocks({
            mixins: [mockMixin],
            props: {
                modelValue: {
                    address: {
                        city: "POWELL",
                        country: "US",
                        state: "OH",
                        streetAddress: "3938 POWELL RD",
                        zipCode: "43065",
                    },
                    distanceInMiles: 16.2690495685233,
                    providerNumber: "003341",
                },
                serviceZipCode: "43081",
                selectedAppointmentType: "Dropoff",
                cmsWidgetName: cmsWidgetName,
                isDisplayed: true,
                shopProviderData: null,
            },
            mountOptions: {
                attachTo: document.body,
            },
        });

        // Act
        await wrapper.setProps({
            shopProviderData: alsoShopQuestionInitialData,
        });

        await wrapper.vm.$nextTick();
        await wrapper.vm.$nextTick();
        await wrapper.vm.$nextTick();
        await wrapper.vm.$nextTick();

        const showMoreShopsLink = wrapper.findComponent({ ref: "showMoreShopsLink" });

        // Assert
        expect(showMoreShopsLink.exists()).toBeTruthy();
        expect(showMoreShopsLink.isVisible()).toBeTruthy();
    });

    it("Should not display the 'Show more locations' link when there are fewer than three locations to chose from", async () => {
        // Arrange
        const alsoShopQuestionInitialData = {
            shopProviders: [
                {
                    address: {
                        city: "WESTERVILLE",
                        country: "US",
                        state: "OH",
                        streetAddress: "4403 EXECUTIVE PKWY",
                        zipCode: "43081",
                    },
                    distanceInMiles: 5.16769294095201,
                    providerNumber: "003335",
                },
                {
                    address: {
                        city: "WORTHINGTON",
                        country: "US",
                        state: "OH",
                        streetAddress: "760 DEARBORN PARK LN",
                        zipCode: "43085",
                    },
                    distanceInMiles: 10.5865432478478,
                    providerNumber: "001820",
                },
            ],
        };

        const { wrapper } = setupMocks({
            mixins: [mockMixin],
            props: {
                modelValue: {
                    address: {
                        city: "POWELL",
                        country: "US",
                        state: "OH",
                        streetAddress: "3938 POWELL RD",
                        zipCode: "43065",
                    },
                    distanceInMiles: 16.2690495685233,
                    providerNumber: "003341",
                },
                serviceZipCode: "43081",
                selectedAppointmentType: "Dropoff",
                cmsWidgetName: cmsWidgetName,
                isDisplayed: true,
                shopProviderData: null,
            },
            mountOptions: {
                attachTo: document.body,
            },
        });

        // Act
        await wrapper.setProps({
            shopProviderData: alsoShopQuestionInitialData,
        });

        await wrapper.vm.$nextTick();

        const showMoreShopsLink = wrapper.findComponent({ ref: "showMoreShopsLink" });

        await wrapper.vm.$nextTick();

        // Assert
        expect(showMoreShopsLink.exists()).toBeFalsy();
    });

    //TODO: Add test to ensure the "Show more locations" link is not visible when all the existing shops are displayed.

    it("Should display the next three shops when the 'Show more locations' link is clicked", async () => {
        // Arrange
        const displayedAnswers = [
            {
                buttonBodyCopy: "4403 Executive Pkwy, Westerville, OH 43081",
                buttonLabel: "Westerville",
                buttonLabelSubCopy: "5 mi",
                value: "003335",
            },
            {
                buttonBodyCopy: "760 Dearborn Park Ln, Worthington, OH 43085",
                buttonLabel: "Worthington",
                buttonLabelSubCopy: "10.5 mi",
                value: "001820",
            },
            {
                buttonBodyCopy: "5015 N High St, Columbus, OH 43214",
                buttonLabel: "Columbus",
                buttonLabelSubCopy: "11.5 mi",
                value: "003343",
            },
        ];

        const { wrapper } = setupMocks({
            mixins: [mockMixin],
            props: {
                modelValue: {
                    address: {
                        city: "POWELL",
                        country: "US",
                        state: "OH",
                        streetAddress: "3938 POWELL RD",
                        zipCode: "43065",
                    },
                    distanceInMiles: 16.2690495685233,
                    providerNumber: "003341",
                },
                serviceZipCode: "43081",
                selectedAppointmentType: "Dropoff",
                cmsWidgetName: cmsWidgetName,
                isDisplayed: true,
                shopProviderData: null,
            },
            mountOptions: {
                attachTo: document.body,
            },
        });

        displayedAnswers.forEach(
            (answer) => (answer.additionalButtonData = wrapper.vm.additionalButtonData)
        );

        // Act
        await wrapper.setProps({
            shopProviderData: shopQuestionInitialData,
        });

        await wrapper.vm.$nextTick();

        wrapper.vm.answers = displayedAnswers;
        wrapper.vm.shopIndex = 3;

        await wrapper.vm.$nextTick();
        await wrapper.vm.$nextTick();
        await wrapper.vm.$nextTick();
        await wrapper.vm.$nextTick();

        await wrapper.setData({
            displaySeeMoreLocationsLink: true,
        });

        await wrapper.vm.$nextTick();

        const showMoreShopsLink = wrapper.findComponent({ ref: "showMoreShopsLink" });

        await wrapper.vm.$nextTick();

        showMoreShopsLink.trigger("click-event");

        await wrapper.vm.$nextTick();

        // Assert
        expect(wrapper.vm.answers.length).toBe(6);

        expect(wrapper.vm.answers).toEqual([
            {
                buttonBodyCopy: "4403 Executive Pkwy, Westerville, OH 43081",
                buttonLabel: "Westerville",
                buttonLabelSubCopy: "5 mi",
                value: "003335",
                additionalButtonData: wrapper.vm.additionalButtonData,
            },
            {
                buttonBodyCopy: "760 Dearborn Park Ln, Worthington, OH 43085",
                buttonLabel: "Worthington",
                buttonLabelSubCopy: "10.5 mi",
                value: "001820",
                additionalButtonData: wrapper.vm.additionalButtonData,
            },
            {
                buttonBodyCopy: "5015 N High St, Columbus, OH 43214",
                buttonLabel: "Columbus",
                buttonLabelSubCopy: "11.5 mi",
                value: "003343",
                additionalButtonData: wrapper.vm.additionalButtonData,
            },
            {
                buttonBodyCopy: "1670 Harmon Ave, Columbus, OH 43223",
                buttonLabel: "Columbus",
                buttonLabelSubCopy: "16 mi",
                value: "006747",
                additionalButtonData: wrapper.vm.additionalButtonData,
            },
            {
                buttonBodyCopy: "3938 Powell Rd, Powell, OH 43065",
                buttonLabel: "Powell",
                buttonLabelSubCopy: "16.5 mi",
                value: "003341",
                additionalButtonData: wrapper.vm.additionalButtonData,
            },
            {
                buttonBodyCopy: "4580 W Broad St, Columbus, OH 43228",
                buttonLabel: "Columbus",
                buttonLabelSubCopy: "19.5 mi",
                value: "003342",
                additionalButtonData: wrapper.vm.additionalButtonData,
            },
        ]);
    });

    it("Should display the number of shops necessary to show a previously selected shop", async () => {
        // Arrange
        const selectedProvider = {
            providerNumber: "003341",
        };

        const { wrapper } = setupMocks({
            mixins: [mockMixin],
            props: {
                modelValue: selectedProvider,
                serviceZipCode: "43081",
                selectedAppointmentType: "Dropoff",
                cmsWidgetName: cmsWidgetName,
                shopProviderData: null,
            },
            mountOptions: {
                attachTo: document.body,
            },
        });

        // Act
        await wrapper.setProps({
            shopProviderData: shopQuestionInitialData,
        });

        await wrapper.vm.$nextTick();
        await wrapper.vm.$nextTick();
        await wrapper.vm.$nextTick();

        // Assert
        expect(wrapper.vm.answers.length).toEqual(5);
    });

    it("Should reset the answers when the selected appointment type changes", async () => {
        // Arrange
        const { wrapper } = setupMocks({
            mixins: [mockMixin],
            props: {
                modelValue: null,
                selectedAppointmentType: "Dropoff",
                cmsWidgetName: cmsWidgetName,
                shopProviderData: null,
            },
            mountOptions: {
                attachTo: document.body,
            },
        });

        await wrapper.setProps({
            shopProviderData: shopQuestionInitialData,
        });

        // Act
        await wrapper.vm.$nextTick();

        expect(wrapper.vm.answers.length).toEqual(3);

        await wrapper.setProps({
            selectedAppointmentType: "Inshop",
        });

        await wrapper.vm.$nextTick();
        await wrapper.vm.$nextTick();

        // Assert
        expect(wrapper.vm.answers.length).toEqual(3);
    });
});

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

    if (props) resultingMountOptions.propsData = props;

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

    return { wrapper };
}
