// Components
import { shallowMount } from '@vue/test-utils';
import { createTestingPinia } from '@pinia/testing';
import duplicateCheck from '@/layouts/duplicate-check/duplicate-check.vue';

// Supporting Files
import baseMixin from '@/mixins/base-mixin';
import { getMountOptions } from '@/helpers/unit-test-helper.js';
import navigationScenarios from '@/router/router-constants/navigation-scenarios.js';
import { getRandomString } from '@/helpers/data-generation.js';
import { useMainStore } from '@/store';
import settleAllPromises from '@/helpers/layout-helper.js';
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
import coverageStatuses from '@/constants/coverage-statuses';
import coverageType from '@/constants/coverage-type';

// Mock fetchCmsContentForPage
jest.mock('@/helpers/cms-content-helper', () => ({
    fetchCmsContentForPage: jest.fn(),
    doesCopyContainRouterLink: jest.fn()
}));

// Mock our module for promises.
jest.mock('@/helpers/layout-helper.js', () => jest.fn());

function getMountedComponent(mainInitialState = {}, initialData = {}, methodToRunAfterInitializingStore = () => {}) {
    const mountOptions = getMountOptions({
        router: {
            navigate: jest.fn()
        }
    });

    const testingPinia = createTestingPinia({
        initialState: {
            main: mainInitialState
        }
    });
    useMainStore(testingPinia);
    methodToRunAfterInitializingStore();

    mountOptions.global.plugins = [testingPinia];
    mountOptions.data = () => (initialData);

    const apiResponses = { cmsContent: {} };

    settleAllPromises.mockImplementation(() => apiResponses);
    fetchCmsContentForPage.mockImplementation(() => Promise.resolve());

    const wrapper = shallowMount(duplicateCheck, mountOptions);
    wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => {});
    wrapper.vm.setCmsContent = jest.fn();
    wrapper.vm.$router.navigateWithSpinner = jest.fn();
    wrapper.vm.navigateBack = baseMixin.methods.navigateBack;

    return { wrapper };
}

const duplicateOrderText = 'Finish existing claim';

describe('duplicateCheck.vue', () => {
    describe('Rendering', () => {
        test('Should render site header', () => {
            // Arrange
            const wrapper = shallowMount(duplicateCheck, getMountOptions());

            // Act
            const siteHeader = wrapper.findComponent({ ref: 'siteHeader' });

            // Assert
            expect(siteHeader.exists()).toBeTruthy();
        });
        test('Should render sub title', () => {
            // Arrange
            const wrapper = shallowMount(duplicateCheck, getMountOptions());

            // Act
            const siteSubHeader = wrapper.findComponent({ ref: 'siteSubHeader' });

            // Assert
            expect(siteSubHeader.exists()).toBeTruthy();
        });
        test('Should render question subcomponent', () => {
            // Arrange
            const wrapper = shallowMount(duplicateCheck, getMountOptions());

            // Act
            const question = wrapper.findComponent({ ref: 'buttonQuestion' });

            // Assert
            expect(question.exists()).toBeTruthy();
        });
        test('Should render site footer', () => {
            // Arrange
            const wrapper = shallowMount(duplicateCheck, getMountOptions());

            // Act
            const footer = wrapper.findComponent({ ref: 'siteFooter' });

            // Assert
            expect(footer.exists()).toBeTruthy();
        });
    });

    describe('computed properties', () => {
        describe('duplicateOrders computed', () => {
            test('duplicateOrders in store undefined => returns empty list', () => {
                // Arrange
                const { wrapper } = getMountedComponent({
                    applicationUser: {
                        duplicateOrders: undefined
                    }
                });

                // Assert
                expect(wrapper.vm.duplicateOrders.length).toBe(0);
            });
            test('duplicateOrders in store empty => returns empty list', () => {
                // Arrange
                const { wrapper } = getMountedComponent({
                    applicationUser: {
                        duplicateOrders: []
                    }
                });

                // Assert
                expect(wrapper.vm.duplicateOrders.length).toBe(0);
            });
            test('duplicateOrder in store with null vehicle year => returns order with only date in subtext', () => {
                // Arrange
                const referralNumber = getRandomString(6, 6);
                const { wrapper } = getMountedComponent({
                    applicationUser: {
                        duplicateOrders: [
                            {
                                vehicleYear: null,
                                vehicleMake: getRandomString(5, 5),
                                vehicleModel: getRandomString(5, 5),
                                referralNumber,
                                correlationId: getRandomString(5, 5)
                            }
                        ]
                    },
                    order: {
                        policy: {
                            dateOfLoss: '1990-09-23'
                        }
                    }
                });

                const expectedSubtext = '09/23/1990';

                // Assert
                expect(wrapper.vm.duplicateOrders.length).toBe(1);
                expect(wrapper.vm.duplicateOrders[0]).toStrictEqual({
                    Text: duplicateOrderText,
                    Name: referralNumber,
                    SubText: expectedSubtext,
                    value: useMainStore().applicationUser.duplicateOrders[0].correlationId
                });
            });
            test('duplicateOrder in store with null vehicle make => returns order with only date subtext', () => {
                // Arrange
                const referralNumber = getRandomString(6, 6);
                const { wrapper } = getMountedComponent({
                    applicationUser: {
                        duplicateOrders: [
                            {
                                vehicleYear: getRandomString(6, 6),
                                vehicleMake: null,
                                vehicleModel: getRandomString(5, 5),
                                referralNumber,
                                correlationId: getRandomString(6, 6)
                            }
                        ]
                    },
                    order: {
                        policy: {
                            dateOfLoss: '2004-11-01'
                        }
                    }
                });

                const expectedSubtext = '11/01/2004';

                // Assert
                expect(wrapper.vm.duplicateOrders.length).toBe(1);
                expect(wrapper.vm.duplicateOrders[0]).toStrictEqual({
                    Text: duplicateOrderText,
                    Name: referralNumber,
                    SubText: expectedSubtext,
                    value: useMainStore().applicationUser.duplicateOrders[0].correlationId
                });
            });
            test('duplicateOrder in store with null vehicle model => returns order with only date subtext', () => {
                // Arrange
                const referralNumber = getRandomString(6, 6);
                const { wrapper } = getMountedComponent({
                    applicationUser: {
                        duplicateOrders: [
                            {
                                vehicleYear: getRandomString(6, 6),
                                vehicleMake: getRandomString(6, 6),
                                vehicleModel: null,
                                referralNumber,
                                correlationId: getRandomString(6, 6)
                            }
                        ]
                    },
                    order: {
                        policy: {
                            dateOfLoss: '1999-01-15'
                        }
                    }
                });

                const expectedSubtext = '01/15/1999';

                // Assert
                expect(wrapper.vm.duplicateOrders.length).toBe(1);
                expect(wrapper.vm.duplicateOrders[0]).toStrictEqual({
                    Text: duplicateOrderText,
                    Name: referralNumber,
                    SubText: expectedSubtext,
                    value: useMainStore().applicationUser.duplicateOrders[0].correlationId
                });
            });
            test('duplicateOrder in store with all vehicle info => returns order with year, make, model and date in subtext', () => {
                // Arrange
                const referralNumber = getRandomString(6, 6);
                const { wrapper } = getMountedComponent({
                    applicationUser: {
                        duplicateOrders: [
                            {
                                vehicleYear: 'YEAR',
                                vehicleMake: 'make',
                                vehicleModel: 'MoDel',
                                referralNumber,
                                correlationId: getRandomString(6, 6)
                            }
                        ]
                    },
                    order: {
                        policy: {
                            dateOfLoss: '2018-03-01'
                        }
                    }
                });

                const expectedVehicle = 'Year Make Model';
                const expectedDate = '03/01/2018';

                // Assert
                expect(wrapper.vm.duplicateOrders.length).toBe(1);
                expect(wrapper.vm.duplicateOrders[0]).toStrictEqual({
                    Text: duplicateOrderText,
                    Name: referralNumber,
                    SubText: `${expectedVehicle}, ${expectedDate}`,
                    value: useMainStore().applicationUser.duplicateOrders[0].correlationId
                });
            });
        });
    });

    describe('Navigation', () => {
        test('Back button clicked triggers navigation', () => {
            // Arrange

            const { wrapper } = getMountedComponent({});
            wrapper.vm.navigateBack = baseMixin.methods.navigateBack;

            // Act
            wrapper.vm.navigateBack();

            // Assert
            expect(wrapper.vm.$router.navigateWithSpinner).toHaveBeenCalled();
            expect(wrapper.vm.$router.navigateWithSpinner)
                .toHaveBeenCalledWith(navigationScenarios.CLICKED_BACK, undefined);
        });

        describe('forwardButtonAction', () => {
            test('Selected duplicate => load session called', async () => {
                // Arrange
                const selectedAnswer = getRandomString(6, 6);
                const { wrapper } = getMountedComponent({
                    applicationUser: {
                        duplicateOrders: [
                            {
                                vehicleYear: 'YEAR',
                                vehicleMake: 'make',
                                vehicleModel: 'MoDel',
                                responseDate: '2018-03-01T01:12:34',
                                referralNumber: getRandomString(6, 6),
                                correlationId: selectedAnswer
                            }
                        ]
                    }
                });

                wrapper.setData({ selectedAnswer });
                useMainStore().loadSession = jest.fn().mockImplementation(() => Promise.resolve({}));

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

                // Assert
                expect(wrapper.vm.mainStore.loadSession).toHaveBeenCalledTimes(1);
                expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1);
            });
            test('Selected new order => load session not called', async () => {
                // Arrange
                const newOrderSelectionName = getRandomString(6, 6);
                const { wrapper } = getMountedComponent({
                    applicationUser: {
                        duplicateOrders: [
                            {
                                vehicleYear: 'YEAR',
                                vehicleMake: 'make',
                                vehicleModel: 'MoDel',
                                responseDate: '2018-03-01T01:12:34',
                                referralNumber: getRandomString(6, 6),
                                correlationId: getRandomString(6, 6)
                            }
                        ]
                    }
                });

                wrapper.setData({ selectedAnswer: newOrderSelectionName });
                useMainStore().loadSession = jest.fn().mockImplementation(() => Promise.resolve({}));

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

                // Assert
                expect(wrapper.vm.mainStore.loadSession).toHaveBeenCalledTimes(0);
                expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1);
            });
            test('Load session throws error => still navigate forward', async () => {
                // Arrange
                const selectedAnswer = getRandomString(6, 6);
                const { wrapper } = getMountedComponent({
                    applicationUser: {
                        duplicateOrders: [
                            {
                                vehicleYear: 'YEAR',
                                vehicleMake: 'make',
                                vehicleModel: 'MoDel',
                                responseDate: '2018-03-01T01:12:34',
                                referralNumber: getRandomString(6, 6),
                                correlationId: selectedAnswer
                            }
                        ]
                    }
                });

                wrapper.setData({ selectedAnswer });
                const error = 'load session error';
                useMainStore().loadSession = jest.fn().mockImplementation(() => Promise.reject(error));

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

                // Assert
                expect(wrapper.vm.mainStore.loadSession).toHaveBeenCalledTimes(1);
                expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1);
            });
            test('coverageType deductible and policy vehicles returned => CLICKED_FORWARD_POLICY_VERIFIED_WITH_VEHICLES', async () => {
                // Arrange
                const { wrapper } = getMountedComponent({
                    order: {
                        insuranceCoverage: {
                            coverageStatus: coverageStatuses.PENDING,
                            coverageType: coverageType.Deductible
                        },
                        policy: {
                            vehicles: [{ test: 'a' }]
                        }
                    }
                });

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

                // Assert
                expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1);
                expect(wrapper.vm.$router.navigate)
                    .toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD_POLICY_VERIFIED_WITH_VEHICLES, undefined);
            });
            test('coverageType deductible and no policy vehicles returned => CLICKED_FORWARD_POLICY_VERIFIED_NO_VEHICLES', async () => {
                // Arrange
                const { wrapper } = getMountedComponent({
                    order: {
                        insuranceCoverage: {
                            coverageStatus: coverageStatuses.PENDING,
                            coverageType: coverageType.Deductible
                        },
                        policy: {
                            vehicles: []
                        }
                    }
                });

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

                // Assert
                expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1);
                expect(wrapper.vm.$router.navigate)
                    .toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD_POLICY_VERIFIED_NO_VEHICLES, undefined);
            });
            test('coverageType none => CLICKED_FORWARD_POLICY_UNVERIFIED', async () => {
                // Arrange
                const { wrapper } = getMountedComponent({
                    order: {
                        insuranceCoverage: {
                            coverageStatus: coverageStatuses.PENDING,
                            coverageType: coverageType.NONE
                        }
                    }
                });

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

                // Assert
                expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1);
                expect(wrapper.vm.$router.navigate)
                    .toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD_POLICY_UNVERIFIED, undefined);
            });
            // eslint-disable-next-line max-len
            test('coverageType deductible and loaded duplicate with policy vehicle => CLICKED_FORWARD_LOADED_DUPLICATE_WITH_POLICY_VEHICLE', async () => {
                // Arrange
                const vin = getRandomString(17, 17);
                const { wrapper } = getMountedComponent({
                    order: {
                        insuranceCoverage: {
                            coverageStatus: coverageStatuses.PENDING,
                            coverageType: coverageType.Deductible
                        },
                        policy: {
                            vehicles: [{ vin }]
                        },
                        vehicle: {
                            vin
                        },
                        loadedFromDupeCheck: true
                    }
                });

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

                // Assert
                expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1);
                expect(wrapper.vm.$router.navigate)
                    .toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD_LOADED_DUPLICATE_WITH_POLICY_VEHICLE, undefined);
            });
            // eslint-disable-next-line max-len
            test('coverageType deductible and loaded duplicate with non policy vehicle => CLICKED_FORWARD_LOADED_DUPLICATE_WITH_NON_POLICY_VEHICLE', async () => {
                // Arrange
                const vin = getRandomString(17, 17);
                const { wrapper } = getMountedComponent({
                    order: {
                        insuranceCoverage: {
                            coverageStatus: coverageStatuses.PENDING,
                            coverageType: coverageType.Deductible
                        },
                        policy: {
                            vehicles: [{ vin }]
                        },
                        vehicle: {
                            vin: null
                        },
                        loadedFromDupeCheck: true
                    }
                });

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

                // Assert
                expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1);
                expect(wrapper.vm.$router.navigate)
                    .toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD_LOADED_DUPLICATE_WITH_NON_POLICY_VEHICLE, undefined);
            });
            // eslint-disable-next-line max-len
            test('coverageType deductible and loaded duplicate with no policy vehicles => CLICKED_FORWARD_LOADED_DUPLICATE_WITH_NO_POLICY_VEHICLES', async () => {
                // Arrange
                const { wrapper } = getMountedComponent({
                    order: {
                        insuranceCoverage: {
                            coverageStatus: coverageStatuses.PENDING,
                            coverageType: coverageType.Deductible
                        },
                        policy: {
                            vehicles: []
                        },
                        vehicle: {
                            vin: null
                        },
                        loadedFromDupeCheck: true
                    }
                });

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

                // Assert
                expect(wrapper.vm.$router.navigate).toHaveBeenCalledTimes(1);
                expect(wrapper.vm.$router.navigate)
                    .toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD_LOADED_DUPLICATE_WITH_NO_POLICY_VEHICLES, undefined);
            });
        });
    });
});
