// Components
import addressLookup from "@/layouts/address-lookup/address-lookup.vue";

// Supporting Files
import { settleAllPromises } from "@/helpers/layout-helper.js";
import { shallowMount } from "@vue/test-utils";
import { getMountOptions } from "@/helpers/unit-test-helper.js";
import { storeActions } from "@/constants/store-actions";
import { storeMutations } from "@/constants/store-mutations";
import { navigationScenarios } from "@/router/router-constants/navigation-scenarios";
import store from "@/store";
import { experimentSettings } from "@/constants/experiments";

jest.mock("@/helpers/damage-helper", () => ({
    isGlassAvailableForCarId: jest.fn().mockImplementation(() => true),
    getDamageString: jest.fn(),
}));

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

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

describe("address-lookup.vue", () => {
    describe("page level alerts", () => {
        test("if the address is not serviceable display the Non-Serviceable Zip Alert", async () => {
            // Arrange
            const mockRegistrationAddress = {
                streetAddress: "1234 Main St",
                city: "Columbus",
                state: "OH",
                zipCode: "43215",
            };

            const { wrapper } = setupMocks({
                isZipValid: true,
                isZipServiceable: false,
                vinVehicles: [
                    {
                        vin: "TEST_VIN",
                        vehicle: {
                            carId: "C0000",
                        },
                    },
                ],
            });

            store.commit(storeMutations.UPDATE_CAR_ID, "CARID");

            await wrapper.setData({
                customerQuestions: {
                    addressQuestions: mockRegistrationAddress,
                },
            });

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

            // Assert
            expect(wrapper.findComponent({ ref: "alertNonServiceableZip" }).isVisible()).toBe(true);
        });

        test("if the address matches a different vehicle display the Matched Different VehicleAlert", async () => {
            // Arrange
            const mockRegistrationAddress = {
                streetAddress: "1234 Main St",
                city: "Columbus",
                state: "OH",
                zipCode: "43215",
            };

            const { wrapper } = setupMocks({
                isZipServiceable: true,
                vinVehicles: [
                    {
                        vehicle: {
                            carId: "C00000",
                        },
                    },
                ],
            });

            store.commit(storeMutations.UPDATE_CAR_ID, "CARID2");

            await wrapper.setData({
                customerQuestions: {
                    addressQuestions: mockRegistrationAddress,
                },
            });

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

            // Assert
            expect(wrapper.findComponent({ ref: "alertMatchedDifferentVehicle" }).isVisible()).toBe(
                true
            );
        });

        test("if the looking up VIN by address is not allowed in the state selected display the Vin Lookup By HomeAddress Not Allowed Alert", async () => {
            // Arrange
            const mockRegistrationAddress = {
                streetAddress: "1234 Main St",
                city: "Columbus",
                state: "OH",
                zipCode: "43215",
            };

            const { wrapper } = setupMocks({
                isZipServiceable: true,
                isStatePermissible: false,
                lookupVinbyAddressResponse: {
                    isStatePermissible: false,
                    vinVehicles: [
                        {
                            vin: "TEST_VIN",
                            vehicle: {
                                carId: "CARID",
                            },
                        },
                        {
                            vin: "TEST_VIN2",
                            vehicle: {
                                carId: "CARID2",
                            },
                        },
                    ],
                },
            });

            store.commit(storeMutations.UPDATE_CAR_ID, "CARID");

            await wrapper.setData({
                customerQuestions: {
                    addressQuestions: mockRegistrationAddress,
                },
            });

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

            // Assert
            expect(
                wrapper.findComponent({ ref: "alertVinLookupsByHomeAddressNotAllowed" }).isVisible()
            ).toBe(true);
        });

        test("if no vehicles found, display Vin Not Found alert", async () => {
            // Arrange
            const mockRegistrationAddress = {
                streetAddress: "1234 Main St",
                city: "Columbus",
                state: "OH",
                zipCode: "43215",
            };

            const { wrapper } = setupMocks({
                isZipServiceable: true,
                lookupVinbyAddressResponse: {
                    isStatePermissible: true,
                    vinVehicles: [], // Return no vehicles
                },
            });

            store.commit(storeMutations.UPDATE_CAR_ID, "CARID");

            await wrapper.setData({
                customerQuestions: {
                    addressQuestions: mockRegistrationAddress,
                },
            });

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

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

            // Assert
            expect(wrapper.findComponent({ ref: "alertVinNotFound" }).isVisible()).toBe(true);
        });
    });

    describe("navigation", () => {
        test("if the back button is clicked, navigate back", async () => {
            // Arrange
            const { wrapper } = setupMocks({
                isZipServiceable: true,
            });

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

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

        test("if the car entered matches one of the vehicles found and the zip is serviceable, navigate forward", async () => {
            // Arrange
            const mockRegistrationAddress = {
                streetAddress: "1234 Main St",
                city: "Columbus",
                state: "OH",
                zipCode: "43215",
            };

            const { wrapper } = setupMocks({
                isZipServiceable: true,
                vinVehicles: [
                    {
                        vehicle: {
                            carId: "C11111",
                        },
                    },
                ],
            });

            await wrapper.setData({
                previouslyEnteredCarId: "C11111",
                customerQuestions: {
                    addressQuestions: mockRegistrationAddress,
                },
            });

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

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

            // Assert
            expect(wrapper.vm.navigateForward).toHaveBeenCalled();
        });

        test("if the car entered does not match any of the multiple vehicles found, navigate to address-vehicles page", async () => {
            // Arrange
            const mockRegistrationAddress = {
                streetAddress: "1234 Main St",
                city: "Columbus",
                state: "OH",
                zipCode: "43215",
            };

            const { wrapper } = setupMocks({
                isZipServiceable: true,
                isStatePermissible: true,
                vinVehicles: [
                    {
                        vin: "TEST_VIN",
                        vehicle: {
                            carId: "CARID",
                        },
                    },
                    {
                        vin: "TEST_VIN2",
                        vehicle: {
                            carId: "CARID2",
                        },
                    },
                ],
            });

            store.commit(storeMutations.UPDATE_CAR_ID, "CARID_A");

            const carsFound = [
                {
                    vin: "TEST_VIN",
                    vehicle: {
                        carId: "CARID",
                    },
                },
                {
                    vin: "TEST_VIN2",
                    vehicle: {
                        carId: "CARID2",
                    },
                },
            ];

            await wrapper.setData({
                customerQuestions: {
                    addressQuestions: mockRegistrationAddress,
                },
            });

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

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

            // Assert
            expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledWith(
                navigationScenarios.CLICKED_FORWARD_WITH_MULTIPLE_VEHICLES,
                undefined,
                {},
                {},
                carsFound
            );
        });

        test("if the car entered matches one of the vehicles found but the zip is NOT serviceable, do not navigate forward", async () => {
            // Arrange
            const mockRegistrationAddress = {
                streetAddress: "1234 Main St",
                city: "Columbus",
                state: "OH",
                zipCode: "43215",
            };

            const { wrapper } = setupMocks({
                isZipServiceable: false,
                isStatePermissible: true,
                vinVehicles: [
                    {
                        vin: "TEST_VIN",
                        vehicle: {
                            carId: "CARID",
                        },
                    },
                    {
                        vin: "TEST_VIN2",
                        vehicle: {
                            carId: "CARID2",
                        },
                    },
                ],
            });

            store.commit(storeMutations.UPDATE_CAR_ID, "CARID");

            await wrapper.setData({
                customerQuestions: {
                    addressQuestions: mockRegistrationAddress,
                },
            });

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

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

            // Assert
            expect(wrapper.vm.navigateForward).toHaveBeenCalledTimes(0);
        });

        test("if a different vehicle is found than the one entered and the selected glass is not available for that vehicle, navigate back to vehicle-damage page", async () => {
            // Arrange
            const mockRegistrationAddress = {
                streetAddress: "1234 Main St",
                city: "Columbus",
                state: "OH",
                zipCode: "43215",
            };

            const { wrapper } = setupMocks({
                isZipServiceable: true,
                isStatePermissible: true,
            });

            await wrapper.setData({
                customerQuestions: {
                    addressQuestions: mockRegistrationAddress,
                },
                isCarIdDifferent: true,
                isSelectedGlassAvailableForVehicle: false,
            });

            let carsFound = [
                {
                    vin: "TEST_VIN2",
                    vehicle: {
                        carId: "C0000",
                    },
                },
            ];

            // Act
            await wrapper.vm.navigateForward(carsFound);

            // Assert
            expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalledWith(
                navigationScenarios.SELECTED_VIN_WITH_MISMATCHED_GLASS,
                undefined,
                {},
                { displayVehicleChangeAlert: true }
            );
        });

        test("single car was found and matches entered vehicle => navigateForwardWithSingleCarMatch", async () => {
            // Arrange

            const carsFound = [
                {
                    vin: "TEST_VIN_2",
                    vehicle: {
                        carId: "C0000",
                    },
                },
            ];

            const { wrapper } = setupMocks({}, {});
            wrapper.vm.navigateForwardWithSingleCarMatch = jest.fn();

            // Act
            wrapper.vm.navigateForward(carsFound);

            // Assert
            expect(wrapper.vm.navigateForwardWithSingleCarMatch).toHaveBeenCalledTimes(1);
        });

        test("multiple cars were found and one matches entered vehicle => navigateForwardWithSingleCarMatch", async () => {
            // Arrange
            const carsFound = [
                {
                    vin: "TEST_VIN_1",
                    vehicle: {
                        carId: "C0000",
                    },
                },
                {
                    vin: "TEST_VIN_2",
                    vehicle: {
                        carId: "CARID2",
                    },
                },
                {
                    vin: "TEST_VIN_3",
                    vehicle: {
                        carId: "CARID3",
                    },
                },
            ];

            const { wrapper } = setupMocks({});
            wrapper.vm.navigateForwardWithSingleCarMatch = jest.fn();

            // Act
            wrapper.vm.navigateForward(carsFound);

            // Assert
            expect(wrapper.vm.navigateForwardWithSingleCarMatch).toHaveBeenCalledTimes(1);
        });
    });

    describe("registration and service zips", () => {
        describe("if registration zip is serviceable", () => {
            test("if registration address is provided => update service address on successful continue", async () => {
                // Arrange
                const mockRegistrationAddress = {
                    streetAddress: "1234 Main St",
                    city: "Columbus",
                    state: "OH",
                    zipCode: "43215",
                };

                const { wrapper } = setupMocks({
                    isZipServiceable: true,
                });

                store.commit(storeMutations.UPDATE_CAR_ID, "CARID");

                await wrapper.setData({
                    customerQuestions: {
                        addressQuestions: mockRegistrationAddress,
                    },
                });

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

                // Assert
                expect(wrapper.vm.dispatchStoreActionWithLogging).toHaveBeenCalledWith(
                    "lookupVinByAddress",
                    {
                        licenseLastName: undefined,
                        licenseState: "OH",
                        licenseStreetAddress: "1234 Main St",
                        licenseZip: "43215",
                    },
                    "address-lookup",
                    false
                );

                expect(wrapper.vm.dispatchStoreActionWithLogging).toHaveBeenCalledWith(
                    "validateZip",
                    {
                        zip: "43215",
                    },
                    "address-lookup"
                );
            });
        });

        describe("if registration zip is not serviceable", () => {
            test("if registration address is provided and user clicks continue => show non-serviceable zip alert", async () => {
                // Arrange
                const mockRegistrationAddress = {
                    streetAddress: "1234 Main St",
                    city: "Columbus",
                    state: "OH",
                    zipCode: "43215",
                };

                const { wrapper } = setupMocks({
                    isZipValid: true,
                    isZipServiceable: false,
                    vinVehicles: [
                        {
                            vin: "TEST_VIN",
                            vehicle: {
                                carId: "C0000",
                            },
                        },
                    ],
                });

                store.commit(storeMutations.UPDATE_CAR_ID, "CARID");

                await wrapper.setData({
                    customerQuestions: {
                        addressQuestions: mockRegistrationAddress,
                    },
                });

                expect(wrapper.findComponent({ ref: "alertNonServiceableZip" }).exists()).toBe(
                    false
                );

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

                // Assert
                expect(wrapper.vm.displayNonServiceableZipAlert).toBe(true);
                expect(wrapper.findComponent({ ref: "alertNonServiceableZip" }).exists()).toBe(
                    true
                );
                expect(wrapper.findComponent({ ref: "alertNonServiceableZip" }).isVisible()).toBe(
                    true
                );
            });

            test("if registration address, service zip are provided, and user clicks continue => don't update service address", async () => {
                // Arrange
                const mockRegistrationAddress = {
                    streetAddress: "1234 Main St",
                    city: "Columbus",
                    state: "OH",
                    zipCode: "43215",
                };

                const { wrapper } = setupMocks({
                    isZipServiceable: false,
                });

                store.commit(storeMutations.UPDATE_CAR_ID, "CARID");

                await wrapper.setData({
                    customerQuestions: {
                        addressQuestions: mockRegistrationAddress,
                    },
                });

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

                //FIX THIS
                // Assert
                expect(wrapper.vm.dispatchStoreAction).not.toHaveBeenCalledWith(
                    storeActions.UPDATE_SERVICE_LOCATION_WITH_VEHICLE_REGISTRATION
                );
            });

            test("if registration address, service zip are provided, and user clicks continue => both zips are saved and are different", async () => {
                // Arrange
                const mockRegistrationAddress = {
                    streetAddress: "1234 Main St",
                    city: "Columbus",
                    state: "OH",
                    zipCode: "43215",
                };

                const { wrapper } = setupMocks({});
                wrapper.vm.navigateForwardWithSingleCarMatch = jest.fn();

                store.commit(storeMutations.UPDATE_CAR_ID, "CARID");

                wrapper.vm.dispatchStoreAction = jest.fn();
                wrapper.vm.dispatchStoreAction.mockImplementation((actionName, value) => {
                    let data = {};
                    if (actionName == storeActions.VALIDATE_ZIP) {
                        if (value == "43215") {
                            data = {
                                isServiceable: false,
                            };
                        } else {
                            data = {
                                isServiceable: true,
                            };
                        }
                    } else if (actionName == storeActions.LOOKUP_VIN_BY_ADDRESS) {
                        data = {
                            isStatePermissible: true,
                            vinVehicles: [
                                {
                                    vin: "TEST_VIN",
                                    vehicle: {
                                        carId: "CARID",
                                    },
                                },
                            ],
                        };
                    }

                    return Promise.resolve({ data });
                });

                await wrapper.setData({
                    customerQuestions: {
                        addressQuestions: mockRegistrationAddress,
                    },
                });

                await wrapper.vm.forwardButtonAction();
                await wrapper.setData({
                    serviceZipCode: "12345",
                });

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

                // // Assert
                expect(wrapper.vm.$store.getters.order.serviceLocation.zipCode).not.toEqual(
                    wrapper.vm.$store.getters.vehicle.registration.zipCode
                );
                expect(wrapper.vm.$store.getters.vehicle.registration.zipCode).toEqual("12345");
                expect(wrapper.vm.$store.getters.order.serviceLocation.zipCode).toEqual("11111");
            });
        });
    });
});

const mockMixin = {
    methods: {
        getSettingValue: jest.fn((settingName) => {
            if (settingName === experimentSettings.IS_EMAIL_OPTIONAL) {
                return "true";
            }
            return "false";
        }),
    },
};

function setupMocks({
    isZipValid = true,
    isZipServiceable = true,
    lookupVinbyAddressResponse,
    partsOrQuestions = [],
    isStatePermissible = true,
    vinVehicles = [],
    carId = "C0000",
}) {
    store.commit(storeMutations.RESET_STATE);
    const wrapper = shallowMount(
        addressLookup,
        getMountOptions({
            actionList: [
                {
                    actionName: storeActions.VALIDATE_ZIP,
                    data: {
                        isValid: isZipValid,
                        isServiceable: isZipServiceable,
                    },
                },
                {
                    actionName: storeActions.LOOKUP_VIN_BY_ADDRESS,
                    data: lookupVinbyAddressResponse
                        ? lookupVinbyAddressResponse
                        : {
                              isStatePermissible: true,
                              vinVehicles: [
                                  {
                                      vin: "TEST_VIN",
                                      vehicle: {
                                          carId: "CARID",
                                      },
                                  },
                              ],
                          },
                },
                {
                    actionName: storeActions.GET_PARTS_OR_QUESTIONS,
                    data: {
                        partsOrQuestions: partsOrQuestions,
                    },
                },
            ],
            router: {
                navigate: jest.fn(),
                navigateWithSaving: jest.fn(),
                navigateWithoutSaving: jest.fn(),
            },
            store: {
                getters: {
                    vehicle: {
                        carId: carId,
                        registration: {
                            licensePlate: "TESTPLATE",
                            zipCode: "12345",
                        },
                    },
                    order: {
                        customer: {
                            emailAddress: "test@test.com",
                        },
                        serviceLocation: {
                            zipCode: "11111",
                        },
                    },
                },
            },
            mixins: [mockMixin],
        })
    );

    const apiResponses = {
        serviceZipValidationResponse: {
            isValid: isZipValid,
            isServiceable: isZipServiceable,
        },
        vinLookupResponse: {
            isStatePermissible: isStatePermissible,
            vinVehicles: vinVehicles,
        },
    };

    settleAllPromises.mockImplementation(() => apiResponses);

    wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => "");
    wrapper.vm.setCmsContent = jest.fn();
    wrapper.vm.$refs.navbar.updateButtonText = jest.fn();
    wrapper.vm.$refs.navbar.removeLoader = jest.fn();

    return { wrapper };
}
