/* eslint-disable max-len */
// Components
import coverageStatement from '@/layouts/coverage-statement/coverage-statement.vue';

// Supporting Files
import { nextTick } from 'vue';
import { shallowMount } from '@vue/test-utils';
import { getEnumName, getMountOptions } from '@/helpers/unit-test-helper.js';
import { createTestingPinia } from '@pinia/testing';
import navigationScenarios from '@/router/router-constants/navigation-scenarios.js';
import { getRandomString, getRandomInt } from '@/helpers/data-generation.js';
import settleAllPromises from '@/helpers/layout-helper.js';
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
import { useMainStore } from '@/store';
import { getPriceOfLineItems } from '@/helpers/price-calculator.js';
import coverageStatuses from '@/constants/coverage-statuses';
import coverageType from '@/constants/coverage-type';

jest.mock('@/helpers/layout-helper.js', () => jest.fn());
jest.mock('@/helpers/price-calculator.js', () => ({
    getPriceOfLineItems: jest.fn()
}));

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

jest.mock('@/helpers/text-helper', () => ({
    createOrderedListFromStringOfParagraphs: jest.fn(),
    createUnorderedListFromStringOfParagraphs: jest.fn(),
    formatAmountInDollars: jest.fn()
}));

const SAFELITE_PROVIDER = 'Safelite';
const CANCEL_CLAIM_REF_NAME = 'CancelClaimModal';

const mockMixin = {
    methods: {
        getCmsContent: jest.fn().mockImplementation(() => ''),
        setCmsContent: jest.fn(),
        onSubmit: jest.fn(),
        onInvalidSubmit: jest.fn(),
        navigateBackByVehicleQuestions: jest.fn()
    }
};

const footerStub = {
    render: () => {},
    methods: {
        updateButtonText: jest.fn()
    }
};

const loadingModalStub = {
    render: () => {},
    methods: {
        showModal: jest.fn(),
        hideModal: jest.fn()
    }
};

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

    mountOptions.global.stubs = {
        ...mountOptions.global.stubs,
        siteFooter: footerStub,
        siteHeader: true,
        recalModal: true,
        contentGroupModal: true,
        alert: true,
        loadingModal: loadingModalStub
    };
    const testingPinia = createTestingPinia({
        initialState: {
            main: mainInitialState
        }
    });
    useMainStore(testingPinia);
    methodToRun();

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

    const apiResponses = {
        supportingItems: []
    };
    const apiPromise = Promise.resolve(apiResponses);
    settleAllPromises.mockImplementation(() => apiPromise);
    fetchCmsContentForPage.mockImplementation(() => Promise.resolve());

    const wrapper = shallowMount(coverageStatement, mountOptions);
    return { wrapper };
}

describe('coverageStatement.vue', () => {
    test('returns the initial data', () => {
        // Arrange
        const mainInitialState = {
            order: {
                damage: {
                    isRepair: true
                },
                insuranceCoverage: {
                    coverageStatus: coverageStatuses.PENDING,
                    coverageType: coverageType.Deductible
                }
            }
        };
        const { wrapper } = getMountedComponent(mainInitialState);

        // Assert
        expect(wrapper.vm.$data).toMatchSnapshot();
    });
    describe('Rendering', () => {
        test('Should render site header', () => {
            // Arrange
            const { wrapper } = getMountedComponent({});

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

            // Assert
            expect(siteHeader.exists()).toBe(true);
        });
        test('Should render site subheader', () => {
            // Arrange
            const { wrapper } = getMountedComponent({});

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

            // Assert
            expect(subheader.exists()).toBe(true);
        });

        test('Should render explanatory text', () => {
            // Arrange
            const { wrapper } = getMountedComponent({});

            // Act
            const explanatoryText = wrapper.find({ ref: 'explanatoryText' });

            // Assert
            expect(explanatoryText.exists()).toBe(true);
        });
        test('Should render secondary text', () => {
            // Arrange
            const { wrapper } = getMountedComponent({});

            // Act
            const secondaryText = wrapper.find({ ref: 'secondaryText' });

            // Assert
            expect(secondaryText.exists()).toBe(true);
        });
    });
    describe('Computed', () => {
        describe.each([
            [false, coverageStatuses.PENDING, coverageType.NONE],
            [false, coverageStatuses.PENDING, coverageType.NO_COMP],
            [false, coverageStatuses.PENDING, coverageType.ITAC],
            [false, coverageStatuses.PENDING, coverageType.Deductible],
            [true, coverageStatuses.VERIFIED, coverageType.NO_COMP],
            [false, coverageStatuses.VERIFIED, coverageType.ITAC],
            [false, coverageStatuses.VERIFIED, coverageType.Deductible],
            [false, coverageStatuses.NO_COVERAGE, coverageType.NONE],
            [false, coverageStatuses.NO_COVERAGE, coverageType.Deductible],
            [false, coverageStatuses.NO_COVERAGE, coverageType.ITAC],
            [false, coverageStatuses.NO_COVERAGE, coverageType.NO_COMP]
        ])('isNoCompQuoteVisible', (expected, status, type) => {
            test(`returns ${expected} when coverageStatus is ${getEnumName(coverageStatuses, status)} coverageType is ${getEnumName(coverageType, type)}`, () => {
                // Arrange
                const mainInitialState = {
                    order: {
                        insuranceCoverage: {
                            coverageStatus: status,
                            coverageType: type
                        }
                    }
                };

                const { wrapper } = getMountedComponent(mainInitialState);

                // Act
                const result = wrapper.vm.isNoCompQuoteVisible;

                // Assert
                expect(result).toBe(expected);
            });
        });

        describe.each([
            [false, coverageStatuses.PENDING, coverageType.NONE],
            [false, coverageStatuses.PENDING, coverageType.NO_COMP],
            [false, coverageStatuses.PENDING, coverageType.ITAC],
            [false, coverageStatuses.PENDING, coverageType.Deductible],
            [false, coverageStatuses.VERIFIED, coverageType.NO_COMP],
            [true, coverageStatuses.VERIFIED, coverageType.ITAC],
            [false, coverageStatuses.VERIFIED, coverageType.Deductible],
            [false, coverageStatuses.NO_COVERAGE, coverageType.NONE],
            [false, coverageStatuses.NO_COVERAGE, coverageType.Deductible],
            [false, coverageStatuses.NO_COVERAGE, coverageType.ITAC],
            [false, coverageStatuses.NO_COVERAGE, coverageType.NO_COMP]
        ])('isITACQuoteVisible', (expected, status, type) => {
            test(`returns ${expected} when coverageStatus is ${getEnumName(coverageStatuses, status)} coverageType is ${getEnumName(coverageType, type)}`, () => {
                // Arrange
                const mainInitialState = {
                    order: {
                        insuranceCoverage: {
                            coverageStatus: status,
                            coverageType: type
                        }
                    }
                };

                const { wrapper } = getMountedComponent(mainInitialState);

                // Act
                const result = wrapper.vm.isITACQuoteVisible;

                // Assert
                expect(result).toBe(expected);
            });
        });

        describe.each([
            [false, coverageStatuses.PENDING, coverageType.NONE],
            [false, coverageStatuses.PENDING, coverageType.NO_COMP],
            [false, coverageStatuses.PENDING, coverageType.ITAC],
            [false, coverageStatuses.PENDING, coverageType.Deductible],
            [false, coverageStatuses.VERIFIED, coverageType.NO_COMP],
            [false, coverageStatuses.VERIFIED, coverageType.ITAC],
            [true, coverageStatuses.VERIFIED, coverageType.Deductible],
            [false, coverageStatuses.NO_COVERAGE, coverageType.NONE],
            [false, coverageStatuses.NO_COVERAGE, coverageType.Deductible],
            [false, coverageStatuses.NO_COVERAGE, coverageType.ITAC],
            [false, coverageStatuses.NO_COVERAGE, coverageType.NO_COMP]
        ])('isDeductibleVisible', (expected, status, type) => {
            test(`returns ${expected} when coverageStatus is ${getEnumName(coverageStatuses, status)} coverageType is ${getEnumName(coverageType, type)}`, () => {
                // Arrange
                const mainInitialState = {
                    order: {
                        insuranceCoverage: {
                            coverageStatus: status,
                            coverageType: type
                        }
                    }
                };

                const { wrapper } = getMountedComponent(mainInitialState);

                // Act
                const result = wrapper.vm.isDeductibleVisible;

                // Assert
                expect(result).toBe(expected);
            });
        });
        describe('isADAS', () => {
            test('returns false when glassParts null', () => {
                // Arrange
                const mainInitialState = {
                    order: {
                        lineItems: {
                            glassParts: null
                        }
                    }
                };
                const { wrapper } = getMountedComponent(mainInitialState);

                // Act
                const result = wrapper.vm.isADAS;

                // Assert
                expect(result).toBeFalsy();
            });
            test('returns false when glassParts empty', () => {
                // Arrange
                const mainInitialState = {
                    order: {
                        lineItems: {
                            glassParts: []
                        }
                    }
                };
                const { wrapper } = getMountedComponent(mainInitialState);

                // Act
                const result = wrapper.vm.isADAS;

                // Assert
                expect(result).toBeFalsy();
            });
            test('returns false when no parts in glassParts require recalibration', () => {
                // Arrange
                const mainInitialState = {
                    order: {
                        lineItems: {
                            glassParts: [
                                {
                                    partNumber: 123,
                                    requiresRecalibration: false
                                },
                                {
                                    partNumber: 111,
                                    requiresRecalibration: false
                                }
                            ]
                        }
                    }
                };
                const { wrapper } = getMountedComponent(mainInitialState);

                // Act
                const result = wrapper.vm.isADAS;

                // Assert
                expect(result).toBeFalsy();
            });
            test('returns true when a part in glassParts require recalibration', () => {
                // Arrange
                const mainInitialState = {
                    order: {
                        lineItems: {
                            glassParts: [
                                {
                                    partNumber: 123,
                                    requiresRecalibration: true
                                },
                                {
                                    partNumber: 111,
                                    requiresRecalibration: false
                                }
                            ]
                        }
                    }
                };
                const { wrapper } = getMountedComponent(mainInitialState);

                // Act
                const result = wrapper.vm.isADAS;

                // Assert
                expect(result).toBeTruthy();
            });
        });
        describe('isQuoteDisplayed', () => {
            describe.each([
                [false, coverageStatuses.PENDING, coverageType.NONE],
                [false, coverageStatuses.PENDING, coverageType.ITAC],
                [false, coverageStatuses.PENDING, coverageType.NO_COMP],
                [false, coverageStatuses.PENDING, coverageType.Deductible],
                [true, coverageStatuses.VERIFIED, coverageType.NO_COMP],
                [false, coverageStatuses.VERIFIED, coverageType.ITAC],
                [false, coverageStatuses.VERIFIED, coverageType.Deductible],
                [false, coverageStatuses.NO_COVERAGE, coverageType.NO_COMP],
                [false, coverageStatuses.NO_COVERAGE, coverageType.ITAC],
                [false, coverageStatuses.NO_COVERAGE, coverageType.Deductible]
            ])('isQuoteDisplayed', (expected, status, type) => {
                // eslint-disable-next-line max-len
                test(`$returns ${expected} when coverageStatus is ${getEnumName(coverageStatuses, status)} and coverageType is ${getEnumName(coverageType, type)}`, () => {
                    // Arrange
                    const mainInitialState = {
                        order: {
                            insuranceCoverage: {
                                coverageStatus: status,
                                coverageType: type
                            }
                        }
                    };
                    const { wrapper } = getMountedComponent(mainInitialState);

                    // Act
                    const result = wrapper.vm.isQuoteDisplayed;

                    // Assert
                    expect(result).toBe(expected);
                });
            });
        });
        describe.each([
            [false, false, true, true, 0],
            [false, true, false, true, 0],
            [false, true, true, false, 0],
            [false, true, true, true, -1],
            [false, true, true, true, null],
            [true, true, true, true, 0]
        ])('shouldRegisterClaim', (
            expected,
            isClaimRegistrationRequired,
            isPolicyLookupSuccessful,
            isPendingClaimRegistration,
            policyVehicleId
        ) => {
            test(`returns ${expected} when isClaimRegistrationRequired is ${isClaimRegistrationRequired} `
           + `and isPolicyLookupSuccessful is ${isPolicyLookupSuccessful} `
           + `and isPendingClaimRegistration is ${isPendingClaimRegistration} `
           + `and policyVehicleId is ${(policyVehicleId == null ? 'NULL' : policyVehicleId)}`, () => {
                // Arrange
                const mainInitialState = {
                    order: {
                        insuranceCoverage: {
                            coverageStatus: isPendingClaimRegistration ? coverageStatuses.PENDING : coverageStatuses.VERIFIED,
                            coverageType: isPolicyLookupSuccessful ? coverageType.Deductible : coverageType.NONE
                        },
                        vehicle: {
                            policyVehicleId
                        }
                    },
                    issConfig: {
                        isClaimRegistrationRequired
                    }
                };

                const { wrapper } = getMountedComponent(mainInitialState);

                // Act
                const result = wrapper.vm.shouldRegisterClaim;

                // Assert
                expect(result).toBe(expected);
            });
        });
    });
    describe('methods', () => {
        describe('arePagePrerequisitesValid', () => {
            test('returns false if car id not set', () => {
                // Arrange
                const mainInitialState = {
                    order: {
                        vehicle: {
                            carId: null
                        }
                    }
                };
                const { wrapper } = getMountedComponent(mainInitialState);

                // Act
                const result = wrapper.vm.arePagePrerequisitesValid();

                // Assert
                expect(result).toBeFalsy();
            });
            test('returns false if car id set to 0', () => {
                // Arrange
                const mainInitialState = {
                    order: {
                        vehicle: {
                            carId: 0
                        }
                    }
                };
                const { wrapper } = getMountedComponent(mainInitialState);

                // Act
                const result = wrapper.vm.arePagePrerequisitesValid();

                // Assert
                expect(result).toBeFalsy();
            });
            test.each([[-1], [1], [123]])('returns true if car id set to %p', (carId) => {
                // Arrange
                const mainInitialState = {
                    order: {
                        vehicle: { carId }
                    }
                };
                const { wrapper } = getMountedComponent(mainInitialState);

                // Act
                const result = wrapper.vm.arePagePrerequisitesValid();

                // Assert
                expect(result).toBeTruthy();
            });
        });
        describe('navigateForward', () => {
            const servicePrice = 82;
            beforeEach(() => {
                getPriceOfLineItems.mockImplementation(() => servicePrice);
            });
            test('If Unverified, navigate forward with CLICKED_FORWARD scenario', () => {
                // Arrange
                const mainInitialState = {
                    order: {
                        damage: {
                            isRepair: true
                        },
                        insuranceCoverage: {
                            coverageStatus: coverageStatuses.PENDING,
                            coverageType: coverageType.NONE
                        },
                        currentDeductible: {
                            repair: null,
                            replace: null
                        }
                    }
                };
                const { wrapper } = getMountedComponent(mainInitialState);

                // Act
                wrapper.vm.navigateForward();

                // Assert
                expect(wrapper.vm.$router.navigate)
                    .toHaveBeenCalledWith(
                        navigationScenarios.CLICKED_FORWARD,
                        undefined
                    );
            });
            test('If Verified Deductible, navigate forward with CLICKED_FORWARD scenario', () => {
                // Arrange
                const deductible = servicePrice - 1;
                const mainInitialState = {
                    order: {
                        damage: {
                            isRepair: true
                        },
                        insuranceCoverage: {
                            coverageStatus: coverageStatuses.VERIFIED,
                            coverageType: coverageType.Deductible
                        },
                        currentDeductible: {
                            replace: deductible
                        }
                    }
                };
                const { wrapper } = getMountedComponent(mainInitialState);

                // Act
                wrapper.vm.navigateForward();

                // Assert
                expect(wrapper.vm.$router.navigate)
                    .toHaveBeenCalledWith(
                        navigationScenarios.CLICKED_FORWARD,
                        undefined
                    );
            });
            test('If Verified ITAC and selected Safelite, navigate forward with CLICKED_FORWARD_WITH_SAFELITE scenario', () => {
                // Arrange
                const deductible = servicePrice + 1;
                const mainInitialState = {
                    order: {
                        damage: {
                            isRepair: true
                        },
                        insuranceCoverage: {
                            coverageStatus: coverageStatuses.VERIFIED,
                            coverageType: coverageType.ITAC
                        },
                        currentDeductible: {
                            replace: deductible
                        }
                    }
                };
                const { wrapper } = getMountedComponent(mainInitialState);
                wrapper.setData({
                    selectedProvider: SAFELITE_PROVIDER
                });

                // Act
                wrapper.vm.navigateForward();

                // Assert
                expect(wrapper.vm.$router.navigate)
                    .toHaveBeenCalledWith(
                        navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE,
                        undefined
                    );
            });
            test('If Verified ITAC, selected Cancel, navigate forward w/ CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP', () => {
                // Arrange
                const deductible = servicePrice + 1;
                const mainInitialState = {
                    order: {
                        damage: {
                            isRepair: true
                        },
                        insuranceCoverage: {
                            coverageStatus: coverageStatuses.VERIFIED,
                            coverageType: coverageType.ITAC
                        },
                        currentDeductible: {
                            replace: deductible
                        }
                    }
                };
                const { wrapper } = getMountedComponent(mainInitialState);
                wrapper.setData({
                    selectedProvider: 'Other'
                });

                // Act
                wrapper.vm.cancelClaim();

                // Assert
                expect(wrapper.vm.$router.navigate)
                    .toHaveBeenCalledWith(
                        navigationScenarios.CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP,
                        undefined
                    );
            });
            test('If No Comp and selected Safelite, navigate forward with CLICKED_FORWARD_WITH_SAFELITE scenario', () => {
                // Arrange
                const mainInitialState = {
                    order: {
                        damage: {
                            isRepair: true
                        },
                        insuranceCoverage: {
                            coverageStatus: coverageStatuses.VERIFIED,
                            coverageType: coverageType.NO_COMP
                        }
                    },
                    issConfig: {
                        enableNoCompQuote: true
                    }
                };
                const { wrapper } = getMountedComponent(mainInitialState);
                wrapper.setData({
                    selectedProvider: SAFELITE_PROVIDER
                });

                // Act
                wrapper.vm.navigateForward();

                // Assert
                expect(wrapper.vm.$router.navigate)
                    .toHaveBeenCalledWith(
                        navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE,
                        undefined
                    );
            });
            test('If No comp and selected other shop, navigate forward with CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP ', () => {
                // Arrange
                const mainInitialState = {
                    order: {
                        damage: {
                            isRepair: true
                        },
                        insuranceCoverage: {
                            coverageStatus: coverageStatuses.VERIFIED,
                            coverageType: coverageType.NO_COMP
                        }
                    },
                    issConfig: {
                        enableNoCompQuote: true
                    }
                };
                const { wrapper } = getMountedComponent(mainInitialState);
                wrapper.setData({
                    selectedProvider: 'other'
                });

                // Act
                wrapper.vm.cancelClaim();

                // Assert
                expect(wrapper.vm.$router.navigate)
                    .toHaveBeenCalledWith(
                        navigationScenarios.CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP,
                        undefined
                    );
            });
        });
    });
    describe('claim registration api call', () => {
        it('Loaded duplicate with previously registered claim => claim registration is not called', async () => {
            // Arrange
            const sellingPrice = getRandomInt(50, 100);
            const deductible = sellingPrice - 1;
            const initialStore = {
                order: {
                    insuranceCoverage: {
                        coverageStatus: coverageStatuses.VERIFIED,
                        coverageType: coverageType.Deductible,
                        claimNumber: getRandomString(10, 10)
                    },
                    policy: {
                        deductible: {
                            repair: deductible
                        }
                    },
                    damage: {
                        isRepair: false
                    }
                },
                issConfig: {
                    isClaimRegistrationRequired: true
                }
            };
            const mockStoreActions = () => {
                useMainStore().getWipers = jest.fn().mockImplementation(() => Promise.resolve());
                useMainStore().getRainDefense = jest.fn().mockImplementation(() => Promise.resolve());
                useMainStore().getSupportingItems = jest.fn().mockImplementation(() => Promise.resolve());
                useMainStore().getInsurancePriceOrderItems = jest.fn().mockImplementation(() => Promise.resolve([
                    {
                        sellingPrice,
                        kitPrice: 0,
                        laborAmount: 0
                    }
                ]));
                useMainStore().getITACPriceOrderItems = jest.fn().mockImplementation(() => Promise.resolve([
                    {
                        sellingPrice,
                        kitPrice: 0,
                        laborAmount: 0
                    }
                ]));
            };
            const { wrapper } = getMountedComponent(initialStore, {}, mockStoreActions);
            const next = (method) => { method(wrapper.vm); };

            // Act
            coverageStatement.beforeRouteEnter.call(wrapper.vm, undefined, undefined, next);
            for (let i = 0; i < 7; i++) {
                // eslint-disable-next-line no-await-in-loop
                await nextTick();
            }

            // Assert
            expect(wrapper.vm.mainStore.registerClaim).toHaveBeenCalledTimes(0);
        });
        it('claim registration not required => method not called', async () => {
            // Arrange
            const mockStoreActions = () => {
                useMainStore().getWipers = jest.fn().mockImplementation(() => Promise.resolve());
                useMainStore().getRainDefense = jest.fn().mockImplementation(() => Promise.resolve());
                useMainStore().getSupportingItems = jest.fn().mockImplementation(() => Promise.resolve());
                useMainStore().getInsurancePriceOrderItems = jest.fn().mockImplementation(() => Promise.resolve());
                useMainStore().getITACPriceOrderItems = jest.fn().mockImplementation(() => Promise.resolve());
            };
            const { wrapper } = getMountedComponent({
                issConfig: {
                    isClaimRegistrationRequired: false
                }
            }, {}, mockStoreActions);
            const next = (method) => { method(wrapper.vm); };

            // Act
            coverageStatement.beforeRouteEnter.call(wrapper.vm, undefined, undefined, next);
            for (let i = 0; i < 7; i++) {
                // eslint-disable-next-line no-await-in-loop
                await nextTick();
            }

            // Assert
            expect(wrapper.vm.mainStore.registerClaim).not.toHaveBeenCalled();
        });

        it('claim registration required => register claim method called', async () => {
            // Arrange
            const servicePrice = 7283;
            const deductible = servicePrice - 1;
            const initialStore = {
                order: {
                    insuranceCoverage: {
                        coverageStatus: coverageStatuses.PENDING,
                        coverageType: coverageType.Deductible,
                        claimNumber: null
                    },
                    vehicle: {
                        policyVehicleId: 1
                    },
                    currentDeductible: {
                        replace: deductible
                    }
                },
                issConfig: {
                    isClaimRegistrationRequired: true
                }
            };
            getPriceOfLineItems.mockImplementation(() => servicePrice);
            const mockStoreActions = () => {
                useMainStore().getWipers = jest.fn().mockImplementation(() => Promise.resolve());
                useMainStore().getRainDefense = jest.fn().mockImplementation(() => Promise.resolve());
                useMainStore().getSupportingItems = jest.fn().mockImplementation(() => Promise.resolve());
                useMainStore().getInsurancePriceOrderItems = jest.fn().mockImplementation(() => Promise.resolve());
                useMainStore().getITACPriceOrderItems = jest.fn().mockImplementation(() => Promise.resolve());
            };
            const { wrapper } = getMountedComponent(initialStore, {}, mockStoreActions);
            const next = (method) => { method(wrapper.vm); };

            // Act
            await coverageStatement.beforeRouteEnter.call(wrapper.vm, undefined, undefined, next);

            // Assert
            expect(wrapper.vm.mainStore.registerClaim).toHaveBeenCalled();
        });
    });
});
