// Components
import schedule from '@/layouts/schedule-page/schedule-page.vue';

// Supporting Files
import { createTestingPinia } from '@pinia/testing';
import { shallowMount } from '@vue/test-utils';
import { getMountOptions } from '@/helpers/unit-test-helper.js';
import { useMainStore } from '@/store/index.js';

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

const mockMixin = {
    methods: {
        getCmsContent: jest.fn().mockImplementation(() => ''),
        setCmsContent: jest.fn(),
        dispatchStoreAction: jest.fn().mockImplementation((storeAction) => {
            if (storeAction === 'saveSupportingItemsSuppressingStateResetting') {
                return Promise.resolve([
                    {
                        partNumber: 'EARLY BIRD',
                        description: null,
                        partType: 'EARLY BIRD',
                        laborAmount: 0,
                        sellingPrice: 14.99,
                        kitPrice: 0
                    }
                ]);
            }
            return {
                data: {
                    estimatedServiceMinutesMinimum: 90,
                    estimatedServiceMinutesMaximum: 120,
                    days: []
                }
            };
        })
    }
};

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

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

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

    mountOptions.global.stubs = {
        siteFooter: footerStub,
        loadingModal: loadingModalStub
    };

    methodToRun();

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

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

beforeEach(() => {
    const testingPinia = createTestingPinia({
        initialState: {
            main: {
                order: {
                    schedule: {
                        date: '2019-01-01',
                        startTime: '09:00',
                        endTime: '10:00',
                        routeCode: '000'
                    },
                    lineItems: {
                        glassParts: [
                            {
                                partNumber: 'ABC123'
                            }
                        ],
                        supportingItems: []
                    },
                    serviceLocation: {
                        appointmentType: 'Inshop',
                        zipCode: '12345',
                        zipCodeCtu: '01234',
                        provider: {
                            providerNumber: '123'
                        }
                    },
                    damage: {
                        isRepair: false
                    },
                    referralNumber: '1234567'
                },
                payment: {
                    isInsurance: true
                },
                lineItems: {
                    glassParts: [],
                    supportingItems: []
                }
            }
        }
    });
    useMainStore(testingPinia);
});
afterEach(() => {
    jest.clearAllMocks();
});

describe('schedule-page.vue', () => {
    beforeAll(() => {
        Object.defineProperty(window, 'matchMedia', { value: jest.fn().mockImplementation((query) => ({
            matches: false,
            media: query,
            onchange: null,
            addEventListener: jest.fn(),
            removeEventListener: jest.fn(),
            dispatchEvent: jest.fn()
        })),
        writable: true });
    });
    describe('Initial Load', () => {
        test('Should pass arePagePrerequisitesValid with a serviceLocation zipcode [in beforeEach]', () => {
            // Arrange
            const { wrapper } = getShallowMountedComponent();

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

            // Assert
            expect(arePagePrerequisitesValid).toBe(true);
        });
        test('Should fail arePagePrerequisitesValid with no serviceLocation zipcode', () => {
            // Arrange
            const { wrapper } = getShallowMountedComponent();
            wrapper.vm.mainStore.order.serviceLocation.zipCode = null;

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

            // Assert
            expect(arePagePrerequisitesValid).toBeFalsy();
        });
        test('should return newShopTimeSlots when getAvailableDatesMethod is called', async () => {
            // Arrange
            const { wrapper } = getShallowMountedComponent();
            wrapper.vm.selectableDatesData = {
                days: []
            };
            const store = useMainStore();
            store.getShopTimeSlots.mockImplementation(() => ({
                data: {
                    estimatedServiceMinutesMinimum: 90,
                    estimatedServiceMinutesMaximum: 120,
                    days: [
                        {
                            date: '2023-12-01',
                            timeSlots: [
                                {
                                    id: '06747-01820-S-B*20424*7 AM',
                                    startTime: '07:00',
                                    endTime: '08:00',
                                    offerPremium: false
                                }
                            ]
                        }
                    ]
                }
            }));

            // Act
            const newShopTimeSlots = await wrapper.vm.getAvailableDatesMethod(
                '2023-01-01',
                '2023-01-15'
            );

            // Assert
            expect(newShopTimeSlots).toStrictEqual({
                days: [
                    {
                        date: '2023-12-01',
                        timeSlots: [
                            {
                                endTime: '08:00',
                                id: '06747-01820-S-B*20424*7 AM',
                                offerPremium: false,
                                startTime: '07:00'
                            }
                        ]
                    }
                ],
                estimatedServiceMinutesMinimum: 90,
                estimatedServiceMinutesMaximum: 120
            });
        });
        test('Should call API service in days of 15 or less when getAvailableDatesMethod is called with large date ranges', async () => {
            // Arrange
            const { wrapper } = getShallowMountedComponent();
            wrapper.vm.selectableDatesData = {
                days: []
            };
            const store = useMainStore();
            store.getShopTimeSlots.mockImplementation(() => ({
                data: {
                    estimatedServiceMinutesMinimum: 90,
                    estimatedServiceMinutesMaximum: 120,
                    days: []
                }
            }));

            // Act
            await wrapper.vm.getAvailableDates.call(
                wrapper.vm,
                '2023-01-01',
                '2023-03-31',
                'Inshop',
                '123'
            );

            // Assert
            // 2023-01-01 --> 2023-02-05
            // 2023-02-06 --> 2023-03-12
            // 2023-03-13 --> 2023-03-31
            expect(store.getShopTimeSlots).toHaveBeenCalledTimes(6);
        });
    });
    describe('Rendering', () => {
        test('Schedule page loads', () => {
            // Arrange
            const { wrapper } = getShallowMountedComponent();

            // Assert
            expect(wrapper).toBeTruthy();
        });
    });
    describe('schedule page methods...', () => {
        test('getServiceZipCtuCodeFromStore should return zipCodeCtu', () => {
            // Arrange
            const { wrapper } = getShallowMountedComponent();
            wrapper.vm.selectableDatesData = {
                days: []
            };

            // Act
            const testValue = wrapper.vm.getServiceZipCtuCodeFromStore();

            // Assert
            expect(testValue).toStrictEqual('01234');
        });
    });
    test.skip('forwardButtonAction should call route method navigateWithoutSaving', async () => {
        // Arrange
        const { wrapper } = getShallowMountedComponent();
        wrapper.vm.$router.navigate = jest.fn(() => ({}));
        wrapper.vm.selectedTimeSlotInfo = {
            timeSlot: {
                routeCode: 'test-id'
            }
        };

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

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