// Components
import { shallowMount } from '@vue/test-utils';
import { createTestingPinia } from '@pinia/testing';
import contactDetails from '@/layouts/contact-details/contact-details.vue';

// Supporting Files
import baseMixin from '@/mixins/base-mixin';
import { getMountOptions } from '@/helpers/unit-test-helper.js';
import { getRandomString, getRandomInt, getRandomBoolean } from '@/helpers/data-generation.js';
import navigationScenarios from '@/router/router-constants/navigation-scenarios.js';
import { useMainStore } from '@/store/index.js';

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

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

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

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

            // Assert
            expect(siteSubHeader.exists()).toBe(true);
        });
        test('Should render first name question subcomponent', () => {
            // Arrange
            const wrapper = shallowMount(contactDetails, getMountOptions());

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

            // Assert
            expect(firstNameQuestion.exists()).toBe(true);
        });
        test('Should render last name question subcomponent', () => {
            // Arrange
            const wrapper = shallowMount(contactDetails, getMountOptions());

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

            // Assert
            expect(lastNameQuestion.exists()).toBe(true);
        });
        test('Should render email question subcomponent', () => {
            // Arrange
            const wrapper = shallowMount(contactDetails, getMountOptions());

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

            // Assert
            expect(emailQuestion.exists()).toBe(true);
        });
        test('Should render phone number question subcomponent', () => {
            // Arrange
            const wrapper = shallowMount(contactDetails, getMountOptions());

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

            // Assert
            expect(phoneNumberQuestion.exists()).toBe(true);
        });
        test('Should render text updates checkbox subcomponent', () => {
            // Arrange
            const checkboxLabel = getRandomString(50, 100);
            const mockMixin = {
                methods: {
                    getCmsContent: jest.fn().mockImplementation(() => checkboxLabel),
                    setCmsContent: jest.fn()
                }
            };
            const mountOptions = getMountOptions();
            mountOptions.mixins = [mockMixin];
            const wrapper = shallowMount(contactDetails, mountOptions);

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

            // Assert
            expect(textUpdatesCheckbox.exists()).toBe(true);
            expect(wrapper.vm.requestTextUpdatesCheckboxText).toBe(`${checkboxLabel}*`);
        });
        test('Should render technician notes textarea question subcomponent', () => {
            // Arrange
            const wrapper = shallowMount(contactDetails, getMountOptions());

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

            // Assert
            expect(notesQuestion.exists()).toBe(true);
        });
        test('Should render disclaimer text', () => {
            // Arrange
            const disclaimerText = getRandomString(50, 100);
            const mockMixin = {
                methods: {
                    getCmsContent: jest.fn().mockImplementation(() => disclaimerText),
                    setCmsContent: jest.fn()
                }
            };
            const mountOptions = getMountOptions();
            mountOptions.mixins = [mockMixin];
            const wrapper = shallowMount(contactDetails, mountOptions);
            const expectedDisclaimerText = `*${disclaimerText} I also agree to Safelite's`;

            // Act
            const componentText = wrapper.text();

            // Assert
            expect(wrapper.vm.textUpdateDisclaimerText).toBe(`*${disclaimerText}`);
            expect(componentText).toContain(expectedDisclaimerText);
        });
        test('Should render privacy policy link', () => {
            // Arrange
            const wrapper = shallowMount(contactDetails, getMountOptions());

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

            // Assert
            expect(privacyPolicyLink.exists()).toBe(true);
        });
        test('Should render terms of use link', () => {
            // Arrange
            const wrapper = shallowMount(contactDetails, getMountOptions());

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

            // Assert
            expect(termsOfUseLink.exists()).toBe(true);
        });
        test('Should render site footer', () => {
            // Arrange
            const wrapper = shallowMount(contactDetails, getMountOptions());

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

            // Assert
            expect(footer.exists()).toBe(true);
        });
        test('Mocked store with no contact info yields expected data', () => {
            // Arrange
            const mountOptions = getMountOptions();

            const firstName = getRandomString(4, 15);
            const lastName = getRandomString(4, 15);
            const emailAddress = getRandomString(10, 20);
            const servicePhone = getRandomInt(1000000000, 9999999999).toString();
            const mainInitialState = {
                order: {
                    customer: {
                        firstName,
                        lastName,
                        emailAddress
                    },
                    contactInfo: {
                        servicePhone
                    }
                }
            };
            mountOptions.global = {
                plugins: [createTestingPinia({
                    initialState: {
                        main: mainInitialState
                    }
                })]
            };

            const wrapper = shallowMount(contactDetails, mountOptions);

            // Assert
            expect(wrapper.vm.firstName).toBe(firstName);
            expect(wrapper.vm.lastName).toBe(lastName);
            expect(wrapper.vm.emailAddress).toBe(emailAddress);
            expect(wrapper.vm.phoneNumber).toBe(servicePhone);
        });
        test('Mock store with contact info yields expected data', () => {
            // Arrange
            const customer = {
                firstName: getRandomString(4, 15),
                lastName: getRandomString(4, 15),
                emailAddress: getRandomString(10, 20),
                phoneNumber: getRandomInt(1000000000, 9999999999)
            };
            const contactInfo = {
                firstName: getRandomString(4, 15),
                lastName: getRandomString(4, 15),
                emailAddress: getRandomString(10, 20),
                servicePhone: getRandomInt(1000000000, 9999999999),
                requestTextUpdates: getRandomBoolean(),
                notesForTechnician: getRandomString(50, 100)
            };
            const mainInitialState = {
                order: {
                    customer,
                    contactInfo
                }
            };
            const mountOptions = getMountOptions();
            mountOptions.global = {
                plugins: [createTestingPinia({
                    initialState: {
                        main: mainInitialState
                    }
                })]
            };

            const wrapper = shallowMount(contactDetails, mountOptions);

            // Assert
            expect(wrapper.vm.firstName).toBe(contactInfo.firstName);
            expect(wrapper.vm.lastName).toBe(contactInfo.lastName);
            expect(wrapper.vm.emailAddress).toBe(contactInfo.emailAddress);
            expect(wrapper.vm.phoneNumber).toBe(contactInfo.servicePhone);
            expect(wrapper.vm.requestTextUpdates).toBe(contactInfo.requestTextUpdates);
            expect(wrapper.vm.notesForTechnician).toBe(contactInfo.notesForTechnician);
        });
    });

    describe('Navigation', () => {
        test('Back button clicked triggers navigation', () => {
            // Arrange
            const wrapper = shallowMount(contactDetails, getMountOptions({
                router: {
                    navigateWithSpinner: jest.fn()
                }
            }));
            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);
        });
        test('Forward button clicked triggers appropriate navigation when safelite shop', () => {
            // Arrange
            const mountOptions = getMountOptions({
                router: {
                    navigate: jest.fn()
                },
                navigationScenarios
            });
            const mainInitialState = {
                order: {
                    serviceLocation: { IsSafeliteProvider: true }
                }
            };
            mountOptions.global.plugins = [createTestingPinia({
                initialState: {
                    main: mainInitialState
                }
            })];
            const wrapper = shallowMount(contactDetails, mountOptions);

            // Act
            wrapper.vm.forwardButtonAction();

            // Assert
            expect(wrapper.vm.$router.navigate).toHaveBeenCalled();
            expect(wrapper.vm.$router.navigate)
                .toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE_SHOP, undefined);
        });
        test('Forward button clicked triggers appropriate navigation when TPA shop', () => {
            // Arrange
            const mountOptions = getMountOptions({
                router: {
                    navigate: jest.fn()
                },
                navigationScenarios
            });
            const mainInitialState = {
                order: {
                    serviceLocation: { IsSafeliteProvider: false }
                }
            };
            mountOptions.global.plugins = [createTestingPinia({
                initialState: {
                    main: mainInitialState
                }
            })];
            const wrapper = shallowMount(contactDetails, mountOptions);

            // Act
            wrapper.vm.forwardButtonAction();

            // Assert
            expect(wrapper.vm.$router.navigate).toHaveBeenCalled();
            expect(wrapper.vm.$router.navigate)
                .toHaveBeenCalledWith(navigationScenarios.CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP, undefined);
        });
        test('Forward button click updates contact info', () => {
            // Arrange
            const mountOptions = getMountOptions({
                router: {
                    navigate: jest.fn()
                }
            });
            const wrapper = shallowMount(contactDetails, mountOptions);
            const firstName = getRandomString(4, 15);
            const lastName = getRandomString(4, 15);
            const emailAddress = getRandomString(10, 20);
            const phoneNumber = getRandomInt(1000000000, 9999999999).toString();
            const requestTextUpdates = getRandomBoolean();
            const notesForTechnician = getRandomString(1, 100);
            wrapper.setData({
                firstName,
                lastName,
                emailAddress,
                phoneNumber,
                requestTextUpdates,
                notesForTechnician
            });

            // Act
            wrapper.vm.forwardButtonAction();

            // Assert
            expect(useMainStore().updateContactInfo).toHaveBeenCalledWith({
                firstName,
                lastName,
                emailAddress,
                requestTextUpdates,
                notesForTechnician
            });
        });

        test('Forward button click updates phone numbers request text updates', () => {
            // Arrange
            const mountOptions = getMountOptions({
                router: {
                    navigate: jest.fn()
                }
            });
            const wrapper = shallowMount(contactDetails, mountOptions);
            const phoneNumber = getRandomInt(1000000000, 9999999999).toString();
            const requestTextUpdates = true;
            wrapper.setData({
                phoneNumber,
                requestTextUpdates
            });

            // Act
            wrapper.vm.forwardButtonAction();

            // Assert
            expect(useMainStore().updatePhoneNumbers).toHaveBeenCalledWith({
                service: phoneNumber,
                alternative: phoneNumber
            });
        });

        test('Forward button click updates phone numbers dot not request text updates', () => {
            // Arrange
            const mountOptions = getMountOptions({
                router: {
                    navigate: jest.fn()
                }
            });
            const wrapper = shallowMount(contactDetails, mountOptions);
            const phoneNumber = getRandomInt(1000000000, 9999999999).toString();
            const requestTextUpdates = false;
            wrapper.setData({
                phoneNumber,
                requestTextUpdates
            });

            // Act
            wrapper.vm.forwardButtonAction();

            // Assert
            expect(useMainStore().updatePhoneNumbers).toHaveBeenCalledWith({
                home: phoneNumber,
                service: phoneNumber
            });
        });
    });

    test('Mocked store with no contact info yields expected data', () => {
        // Arrange
        const mountOptions = getMountOptions();

        const firstName = getRandomString(4, 15);
        const lastName = getRandomString(4, 15);
        const emailAddress = getRandomString(10, 20);
        const servicePhone = getRandomInt(1000000000, 9999999999);
        const mainInitialState = {
            order: {
                customer: {
                    firstName,
                    lastName,
                    emailAddress
                },
                contactInfo: {
                    firstName: null,
                    lastName: null,
                    emailAddress: null,
                    servicePhone,
                    requestTextUpdates: null,
                    notesForTechnician: null
                }
            }
        };
        mountOptions.global = {
            plugins: [createTestingPinia({
                initialState: {
                    main: mainInitialState
                }
            })]
        };

        const wrapper = shallowMount(contactDetails, mountOptions);

        // Assert
        expect(wrapper.vm.firstName).toBe(firstName);
        expect(wrapper.vm.lastName).toBe(lastName);
        expect(wrapper.vm.emailAddress).toBe(emailAddress);
        expect(wrapper.vm.phoneNumber).toBe(servicePhone);
    });

    test('Mock store with contact info yields expected data', () => {
        // Arrange
        const customer = {
            firstName: getRandomString(4, 15),
            lastName: getRandomString(4, 15),
            emailAddress: getRandomString(10, 20),
            phoneNumber: getRandomInt(1000000000, 9999999999)
        };
        const contactInfo = {
            firstName: getRandomString(4, 15),
            lastName: getRandomString(4, 15),
            emailAddress: getRandomString(10, 20),
            servicePhone: getRandomInt(1000000000, 9999999999),
            requestTextUpdates: getRandomBoolean(),
            notesForTechnician: getRandomString(50, 100)
        };
        const mainInitialState = {
            order: {
                customer,
                contactInfo
            }
        };
        const mountOptions = getMountOptions();
        mountOptions.global = {
            plugins: [createTestingPinia({
                initialState: {
                    main: mainInitialState
                }
            })]
        };

        const wrapper = shallowMount(contactDetails, mountOptions);

        // Assert
        expect(wrapper.vm.firstName).toBe(contactInfo.firstName);
        expect(wrapper.vm.lastName).toBe(contactInfo.lastName);
        expect(wrapper.vm.emailAddress).toBe(contactInfo.emailAddress);
        expect(wrapper.vm.phoneNumber).toBe(contactInfo.servicePhone);
        expect(wrapper.vm.requestTextUpdates).toBe(contactInfo.requestTextUpdates);
        expect(wrapper.vm.notesForTechnician).toBe(contactInfo.notesForTechnician);
    });
});
