// Components
import paymentMethod from '@/layouts/payment-method/payment-method.vue';

// Supporting Files
import { shallowMount } from '@vue/test-utils';
import { createTestingPinia } from '@pinia/testing';
import { getMountOptions } from '@/helpers/unit-test-helper.js';
import { useMainStore, getDefaultState } from '@/store';
import issPageValues from '@/router/router-constants/issPage-values';
import { paymentMethods } from '@/constants/payment-method-constants';
import queryStrings from '@/constants/query-strings';
import { experimentSettings } from '@/constants/experiments';
import { submitWorkOrder } from '@/helpers/order-helper.js';
import coverageStatuses from '@/constants/coverage-statuses';
import coverageType from '@/constants/coverage-type';

// Mock so it can be used as an assertion
jest.mock('@/helpers/order-helper.js', () => ({
    submitWorkOrder: jest.fn(),
    saveSession: jest.fn()
}));

function setupMocks({ customMountOptions = {}, queryString }, mainInitialState = {}, customMixin = null) {
    const mountOptions = getMountOptions({
        ...customMountOptions,
        route: { query: { issPage: issPageValues.PAYMENT_METHOD, ...queryString }, params: {} },
        router: {
            navigate: jest.fn(),
            navigateToExternalUrl: jest.fn()
        }
    });

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

    const mockMixin = customMixin ?? {
        methods: {
            getSettingValue: jest.fn((settingName) => {
                if (settingName === experimentSettings.ISS_DISPLAY_PAY_IN_ADVANCE) {
                    return 'true';
                }

                return 'false';
            })
        }
    };

    mountOptions.global.plugins = [testingPinia];
    mountOptions.global.mixins = [mockMixin];

    const wrapper = shallowMount(paymentMethod, mountOptions);

    return wrapper;
}

beforeEach(() => {
    const store = useMainStore();
    const defaultState = getDefaultState();
    Object.keys(defaultState).forEach((key) => {
        store[key] = defaultState[key];
    });
});

describe('payment-method.vue', () => {
    describe('Payment Method Type', () => {
        test('getting payment method when method is pay later', async () => {
            // Arrange
            const payLaterMethod = paymentMethods.PAY_AT_TIME_OF_SERVICE;
            const store = {
                order: {
                    payment: {
                        paymentMethod: null
                    }
                }
            };
            const wrapper = setupMocks({}, store);

            // Act
            const paymethod = wrapper.vm.getPaymentMethodFromStore();

            // Assert
            expect(paymethod).toBe(payLaterMethod);
        });
        test('getting payment method when method is pay in advance', async () => {
            // Arrange
            const payInAdvanceMethod = paymentMethods.CREDIT_CARD;
            const store = {
                order: {
                    payment: {
                        paymentMethod: payInAdvanceMethod
                    },
                    insuranceCoverage: {
                        coverageStatus: coverageStatuses.VERIFIED,
                        coverageType: coverageType.Deductible
                    },
                    currentDeductible: 1000
                }
            };
            const wrapper = setupMocks({}, store);

            // Act
            const paymethod = wrapper.vm.getPaymentMethodFromStore();

            // Assert
            expect(paymethod).toBe(payInAdvanceMethod);
        });
        test('getting PAY_AT_TIME_OF_SERVICE when deductible is 0', async () => {
            // Arrange
            const payInAdvanceMethod = paymentMethods.PAY_AT_TIME_OF_SERVICE;
            const store = {
                order: {
                    payment: {
                        paymentMethod: payInAdvanceMethod
                    },
                    insuranceCoverage: {
                        coverageStatus: coverageStatuses.VERIFIED,
                        coverageType: coverageType.Deductible
                    },
                    currentDeductible: 0
                }
            };
            const wrapper = setupMocks({}, store);

            // Act
            const paymethod = wrapper.vm.getPaymentMethodFromStore();

            // Assert
            expect(paymethod).toBe(payInAdvanceMethod);
        });
        test('getting PAY_AT_TIME_OF_SERVICE when Unverified', async () => {
            // Arrange
            const payInAdvanceMethod = paymentMethods.PAY_AT_TIME_OF_SERVICE;
            const store = {
                order: {
                    payment: {
                        paymentMethod: payInAdvanceMethod
                    },
                    insuranceCoverage: {
                        coverageStatus: coverageStatuses.PENDING,
                        coverageType: coverageType.Deductible
                    },
                    currentDeductible: 1000
                }
            };
            const wrapper = setupMocks({}, store);

            // Act
            const paymethod = wrapper.vm.getPaymentMethodFromStore();

            // Assert
            expect(paymethod).toBe(payInAdvanceMethod);
        });
        test('getting PAY_AT_TIME_OF_SERVICE when PIA Experiment disabled', async () => {
            // Arrange
            const payInAdvanceMethod = paymentMethods.PAY_AT_TIME_OF_SERVICE;
            const mixin = {
                methods: {
                    getSettingValue: jest.fn((settingName) => {
                        if (settingName === experimentSettings.ISS_DISPLAY_PAY_IN_ADVANCE) {
                            return 'false';
                        }
                        return 'false';
                    })
                }
            };
            const store = {
                order: {
                    payment: {
                        paymentMethod: payInAdvanceMethod
                    },
                    insuranceCoverage: {
                        coverageStatus: coverageStatuses.VERIFIED,
                        coverageType: coverageType.Deductible
                    },
                    currentDeductible: 1000
                }
            };
            const wrapper = setupMocks({}, store, mixin);

            // Act
            const paymethod = wrapper.vm.getPaymentMethodFromStore();

            // Assert
            expect(paymethod).toBe(payInAdvanceMethod);
        });
    });

    describe('Pay In Advance Error Alert', () => {
        test('show pay in advance error alert when contained in querystring', () => {
            // Arrange
            const queryString = {
                [queryStrings.DISPLAY_PAY_IN_ADVANCE_ALERT]: paymentMethods.AFTERPAY
            };
            const wrapper = setupMocks({ queryString });

            // Assert
            const payInAdvanceErrorAlert = wrapper.find('[name="payInAdvanceErrorAlert"]');
            expect(payInAdvanceErrorAlert.exists()).toBeTruthy();
            expect(payInAdvanceErrorAlert.isVisible()).toBeTruthy();
        });

        test('hide pay in advance error alert when not contained in querystring', () => {
            // Arrange
            const wrapper = setupMocks({});

            // Assert
            const payInAdvanceErrorAlert = wrapper.find('[name="payInAdvanceErrorAlert"]');
            expect(payInAdvanceErrorAlert.exists()).toBeFalsy();
        });
    });

    describe('isPayInAdvanceDisabled', () => {
        let store = {};
        let mixin = {
            methods: {
                getSettingValue: jest.fn((settingName) => {
                    if (settingName === experimentSettings.ISS_DISPLAY_PAY_IN_ADVANCE) {
                        return 'true';
                    }
                    return 'false';
                })
            }
        };
        beforeEach(() => {
            store = {
                order: {
                    insuranceCoverage: {
                        coverageStatus: coverageStatuses.VERIFIED,
                        coverageType: coverageType.Deductible
                    },
                    currentDeductible: {
                        replace: 123
                    }
                },
                issConfig: {
                    isClaimRegistrationRequired: true,
                    enableNoCompQuote: true
                },
                applicationUser: {
                    experiments: [
                        {
                            settings: {
                                ISSDisplayPIAInsurance_ISS: 'true'
                            }
                        }
                    ]
                }
            };
        });
        test('returns true when coverageStatus is pending', () => {
            // Arrange
            store.order.insuranceCoverage.coverageStatus = coverageStatuses.PENDING;
            const wrapper = setupMocks({}, store, mixin);

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

            // Assert
            expect(result).toBeTruthy();
        });
        test('returns true when coverageStatus is no coverage', () => {
            // Arrange
            store.order.insuranceCoverage.coverageStatus = coverageStatuses.NO_COVERAGE;
            const wrapper = setupMocks({}, store, mixin);

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

            // Assert
            expect(result).toBeTruthy();
        });
        test('returns false when coverageStatus is verified and deductibleTotal > 0', () => {
            // Arrange
            store.order.insuranceCoverage.coverageStatus = coverageStatuses.VERIFIED;
            store.order.currentDeductible = 34.99;
            const wrapper = setupMocks({}, store, mixin);

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

            // Assert
            expect(result).toBeFalsy();
        });
        test('returns true when coverageStatus is verified and deductibleTotal = 0', () => {
            // Arrange
            store.order.insuranceCoverage.coverageStatus = coverageStatuses.VERIFIED;
            store.order.currentDeductible.replace = 0;
            const wrapper = setupMocks({}, store, mixin);

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

            // Assert
            expect(result).toBeTruthy();
        });
        test('returns true when pia not enabled', () => {
            // Arrange
            mixin = {
                methods: {
                    getSettingValue: jest.fn((settingName) => {
                        if (settingName === experimentSettings.ISS_DISPLAY_PAY_IN_ADVANCE) {
                            return 'false';
                        }
                        return 'true';
                    })
                }
            };
            const wrapper = setupMocks({}, store, mixin);

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

            // Assert
            expect(result).toBeTruthy();
        });
    });

    describe('forwardButtonAction', () => {
        test('Pay at the time of service is selected, should call saveWorkOrder', async () => {
            // Arrange
            const wrapper = setupMocks({});
            wrapper.vm.paymentMethod = paymentMethods.PAY_AT_TIME_OF_SERVICE;

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

            // Assert
            expect(submitWorkOrder).toHaveBeenCalledTimes(1);
        });
    });
});
