<template>
    <Form
        ref="theForm"
        @submit="onSubmit"
        @invalidSubmit="onInvalidSubmit">
        <div class="fade-on-route-transition">
            <div class="justify-content-center">
                <siteHeader
                    cmsWidgetName="SiteHeaderWidget" />
            </div>
            <div class="iss-heritage-container-width">
                <div class="schedule-page-container iss-heritage-content-container-width">
                    <siteSubHeader
                        cmsWidgetName="ScheduleSubHeaderWidget"
                        secondaryTextClasses="text-center small sub-text"
                        class="mt-4" />
                    <div class="service-location-content-container">
                        <serviceLocation
                            ref="serviceLocation"
                            :schedulingInshopAvailabilityRating="inShopAvailabilityRating"
                            @appointmentTypeChanged="appointmentTypeChangedFromServiceLocation"
                            @cityUpdated="cityUpdatedFromServiceLocation"
                            @clearMobileData="clearMobileDataFromServiceLocation"
                            @inShopZipUpdated="inShopZipUpdatedFromServiceLocation"
                            @mobileZipUpdated="mobileZipUpdatedFromServiceLocation"
                            @providerChanged="providerChangedFromServiceLocation" />
                    </div>
                </div>
                <div
                    v-show="hasNeededServiceLocationData"
                    class="date-picker-container iss-heritage-content-container-width">
                    <div class="date-picker-content-container">
                        <locationAlerts
                            ref="locationAlerts"
                            cmsWidgetPrefix="LocationAlert-"
                            :city="selectedServiceLocationCity" />
                        <datePicker
                            ref="datePicker"
                            v-model="selectedTimeSlotInfo"
                            customComponentId="dateQuestion"
                            selectableDatesSetting="custom"
                            class="text-link-small"
                            :activeAppointmentType="selectedAppointmentType"
                            :isMobileView="isMobileView"
                            :showTimeSlotError="showDatePickerError"
                            :customSelectableDatesCallback="getAvailableDatesMethod"
                            @dateSelected="dateSelectedFromPicker"
                            @timeSlotSelected="timeSlotSelectedFromPicker" />
                    </div>
                </div>
                <div class="site-footer-container iss-heritage-content-container-width">
                    <siteFooter
                        ref="navbar"
                        class="mt-5"
                        cmsWidgetName="SiteFooterWidget"
                        :isForwardButtonHidden="!hasNeededServiceLocationData"
                        :isForwardButtonNavigationDisabled="!isFormValid"
                        @backClicked="navigateBack(this, navigateBackScenario)"
                        @forwardClicked="forwardButtonAction" />
                </div>
            </div>
        </div>
        <suggestTimeslotModal
            :ref="SUGGEST_TIMESLOT_MODAL_REF_NAME"
            cmsWidgetName="SuggestTimeslotModal"
            @confirmAppointmentClicked="autoSelectTimeslotConfirmed" />
    </Form>
</template>
<script>
// Components
import siteHeader from '@/iss-components/site-header/site-header.vue';
import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header.vue';
import locationAlerts from '@/layouts/schedule-page/location-alerts/location-alerts.vue';
import datePicker from '@/digital-components/date-picker/date-picker.vue';
import serviceLocation from '@/layouts/schedule-page/service-location/service-location.vue';
import siteFooter from '@/iss-components/site-footer/site-footer.vue';
import suggestTimeslotModal from '@/layouts/schedule-page/suggest-timeslot-modal/suggest-timeslot-modal.vue';

// Supporting files
import { experimentSettings, experimentTest, experimentVariation, experimentUniverses } from '@/constants/experiments';
import {
    AppointmentTypeStrings,
    GET_MOBILE_TIME_SLOTS,
    GET_SHOP_TIME_SLOTS,
    PREMIUM_FEE_PART_TYPE
} from '@/constants/schedule-constants.js';
import {
    fetchCmsContentForPage,
    splitCopyOnCMSPlaceHolder
} from '@/helpers/cms-content-helper';
import {
    calcDaysBetweenDates,
    convertDateToDateString,
    sumDateString
} from '@/helpers/date-helper';
import settleAllPromises from '@/helpers/layout-helper';
import showIssLoadingModal from '@/helpers/loading-modal-helper.js';
import {
    getPricedMobileFeePart,
    getMobileZipCodeData,
    getZipCodeData,
    isServiceableMobileWithData,
    mapTimeSlot
} from '@/helpers/service-location-helper';
import { Form } from 'vee-validate';
import BaseFormMixin from '@/mixins/base-form-mixin.js';
import { useMainStore } from '@/store';

// Define constants
const SUGGEST_TIMESLOT_MODAL_REF_NAME = 'SuggestTimeslotModal';
const TIME_SLOTS_CALL_DAYS_LIMIT = 15;

const getAvailableDates = async (
    startDateString,
    endDateString,
    appointmentType,
    providerNumber,
    mobileZipCodeOverride = null
) => {
    const apiEndDateLimit = sumDateString(
        startDateString,
        TIME_SLOTS_CALL_DAYS_LIMIT - 1
    );
    const difference = calcDaysBetweenDates(startDateString, endDateString);
    const apiCallsCount = Math.ceil(difference / TIME_SLOTS_CALL_DAYS_LIMIT);
    const storeActionConfigs = [];
    let apiStartDate = startDateString;
    let apiEndDate = endDateString;

    for (let i = 1; i <= apiCallsCount; i++) {
        let storeActionConfig;

        if (i > 1) {
            apiStartDate = sumDateString(apiEndDate, 1);
            apiEndDate = sumDateString(
                apiStartDate,
                TIME_SLOTS_CALL_DAYS_LIMIT - 1
            );

            if (i === apiCallsCount) {
                apiEndDate = endDateString;
            }
        } else if (apiEndDate > apiEndDateLimit) {
            apiEndDate = apiEndDateLimit;
        }

        if (appointmentType === AppointmentTypeStrings.MOBILE || appointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP) {
            storeActionConfig = {
                storeAction: GET_MOBILE_TIME_SLOTS,
                payload: {
                    startDate: apiStartDate,
                    endDate: apiEndDate,
                    zipCodeOverride: mobileZipCodeOverride
                }
            };
        } else {
            storeActionConfig = {
                storeAction: GET_SHOP_TIME_SLOTS,
                payload: {
                    startDate: apiStartDate,
                    endDate: apiEndDate,
                    shopAppointmentType: appointmentType,
                    providerNumber
                }
            };
        }
        if (apiStartDate < apiEndDate) storeActionConfigs.push(storeActionConfig);
    }

    const timeSlotsResponsesData = {
        days: []
    };

    function compareDayStrings(a, b) {
        if (a.date < b.date) return -1;
        if (a.date > b.date) return 1;
        return 0;
    }

    const makeParallelCalls = async () => {
        await Promise.all(storeActionConfigs.map(async (storeAction) => {
            let timeSlotsResponse = null;
            if (storeAction.storeAction === GET_SHOP_TIME_SLOTS) {
                if (storeAction.payload.providerNumber) {
                    timeSlotsResponse = await useMainStore().getShopTimeSlots(
                        storeAction.payload.startDate,
                        storeAction.payload.endDate,
                        storeAction.payload.shopAppointmentType,
                        storeAction.payload.providerNumber
                    );
                }
            } else if (storeAction.payload?.zipCodeOverride) {
                timeSlotsResponse = await useMainStore().getMobileTimeSlots(
                    storeAction.payload.startDate,
                    storeAction.payload.endDate,
                    storeAction.payload.zipCodeOverride
                );
            }

            if (!timeSlotsResponse || !timeSlotsResponse.data) {
                return;
            }

            timeSlotsResponsesData.estimatedServiceMinutesMinimum = timeSlotsResponse.data.estimatedServiceMinutesMinimum;
            timeSlotsResponsesData.estimatedServiceMinutesMaximum = timeSlotsResponse.data.estimatedServiceMinutesMaximum;
            timeSlotsResponsesData.days = [
                ...timeSlotsResponsesData.days,
                ...timeSlotsResponse.data.days
            ];
        }));
    };

    return makeParallelCalls().then(() => {
        // sort days chronologically
        timeSlotsResponsesData.days.sort(compareDayStrings);
        return timeSlotsResponsesData;
    })
    .catch(() => {
        return timeSlotsResponsesData;
    });
};

export default {
    name: 'schedule-page',
    components: {
        siteHeader,
        siteSubHeader,
        locationAlerts,
        datePicker,
        serviceLocation,
        siteFooter,
        suggestTimeslotModal,
        Form
    },
    mixins: [BaseFormMixin],
    async beforeRouteEnter(to, from, next) {
        // Call APIs
        const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
        let storeServiceLocation = useMainStore().order.serviceLocation;
        let storeSelectedProvider = storeServiceLocation?.provider;

        const storeSelectedSchedule = useMainStore().order.schedule;
        if (storeSelectedProvider?.providerNumber && !storeSelectedSchedule?.routeCode) {
            useMainStore().resetServiceLocationProvider();
            storeServiceLocation = useMainStore().order.serviceLocation;
            storeSelectedProvider = storeServiceLocation?.provider;
        }
        const storeSelectedAppointmentType = storeServiceLocation?.appointmentType;
        const isMobileAppointment = storeSelectedAppointmentType === AppointmentTypeStrings.MOBILE
                || storeSelectedAppointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP;
        const serviceZipCode = storeServiceLocation?.zipCode || useMainStore().order.customer.address.zipCode;
        const zipCodeData = getZipCodeData(serviceZipCode);
        const mobileFeePartPromise = getPricedMobileFeePart(serviceZipCode);
        const serviceabilityDetailsPromise = useMainStore().getServiceabilityDetails(serviceZipCode);
        const getGlassFeesPromise = useMainStore().getGlassFees();
        const providersPromise = useMainStore().getSafeliteProviders(serviceZipCode, 150);
        const premiumFeePromise = useMainStore().getMobilePremiumFee();
        const premiumFeeWithPricePromise = premiumFeePromise.then((result) => {
            if (result.data) {
                return useMainStore().getCombinedQuote(result.data);
            }
            return result.data;
        });

        // Settle promises and get results
        const promiseResultMap = [
            {
                resultKey: 'cmsContent',
                promise: cmsContentPromise
            },
            {
                resultKey: 'mobileFeePart',
                promise: mobileFeePartPromise
            },
            {
                resultKey: 'glassFees',
                promise: getGlassFeesPromise
            },
            {
                resultKey: 'serviceabilityDetails',
                promise: serviceabilityDetailsPromise
            },
            {
                resultKey: 'zipCodeData',
                promise: zipCodeData
            },
            {
                resultKey: 'providers',
                promise: providersPromise
            },
            {
                resultKey: 'premiumFeeWithPrice',
                promise: premiumFeeWithPricePromise
            }
        ];

        // use resultMap to populate layout content.
        const resultMap = await settleAllPromises(promiseResultMap);
        const providersUnderOneHundredMiles = resultMap.providers?.shopProviders?.filter((provider) => provider.distanceInMiles <= 100);
        const serviceLocationData = {
            defaultMobileZipCode: isMobileAppointment
                ? storeServiceLocation?.zipCode
                : '',
            glassFees: resultMap.glassFees,
            mobileFeePart: resultMap.mobileFeePart,
            providers: {
                ...resultMap.providers,
                shopProviders: providersUnderOneHundredMiles || []
            },
            serviceabilityDetails: resultMap.serviceabilityDetails,
            zipCodeData: resultMap.zipCodeData
        };
        useMainStore().updateIsSafeliteProvider(true);
        next(async (vm) => {
            const foundProviderInFullList = resultMap.providers?.shopProviders
                .find((provider) => provider.providerNumber === storeSelectedProvider?.providerNumber) || null;
            const foundProviderInHundredMiles = providersUnderOneHundredMiles
                .find((provider) => provider.providerNumber === storeSelectedProvider?.providerNumber) || null;

            if (!foundProviderInHundredMiles && !foundProviderInFullList) {
                if (storeSelectedProvider?.providerNumber && resultMap.providers?.shopProviders) {
                    serviceLocationData.providers?.shopProviders.push(storeSelectedProvider);
                }
            } else if (!foundProviderInHundredMiles && foundProviderInFullList) {
                serviceLocationData.providers?.shopProviders.push(foundProviderInFullList);
            }

            const initialServiceLocationObj = {
                mobileProviderNumber: isMobileAppointment
                    ? storeSelectedProvider?.providerNumber
                    : null,
                provider: isMobileAppointment ? null : foundProviderInFullList || resultMap.providers?.shopProviders[0] || null,
                zipCode: useMainStore().order.serviceLocation.zipCode || useMainStore().order.customer.address.zipCode,
                zipCodeCtu: resultMap.zipCodeData?.zipCodeCtu
            };

            const mobileFirstObject = {
                mobileProviderNumber: resultMap.providers?.mobileProviderNumber,
                serviceabilityDetails: resultMap.serviceabilityDetails,
                zipCode: initialServiceLocationObj.zipCode
            };
            
            vm.setCmsContent(resultMap.cmsContent);
            vm.$refs.serviceLocation.initializeComponent(serviceLocationData);
            await vm.setData(resultMap.premiumFeeWithPrice, initialServiceLocationObj);
            await vm.checkMobileFirstExperience(mobileFirstObject);
            showIssLoadingModal(false);
        });
    },
    setup() {
        const mainStore = useMainStore();
        return { mainStore };
    },
    data() {
        return {
            inShopAvailabilityRating: 'high',
            inShopDatesData: [],
            isDatePickerRefreshing: false,
            isMobileView: false,
            mobileDatesData: [],
            mobileFeePart: null,
            mobilePremiumAppointmentFee: null,
            mobileProviderNumber: null,
            selectableDatesData: [],
            selectedAppointmentType: this.getAppointmentType(),
            selectedDate: this.getSelectedDate(),
            selectedMobileZipCode: null,
            selectedProvider: this.getSelectedProvider(),
            selectedServiceLocation: this.getServiceLocation(),
            selectedServiceLocationCity: this.getServiceLocationCity(),
            selectedTimeSlotInfo: this.getSelectedTimeSlotInfo(),
            showDatePickerError: false,
            SUGGEST_TIMESLOT_MODAL_REF_NAME
        };
    },
    computed: {
        hasNeededServiceLocationData() {
            const serviceLocationToUse = this.selectedServiceLocation;
            if (!serviceLocationToUse || !this.selectedAppointmentType) {
                return false;
            }

            const validMobileAppointmentType = ((this.selectedAppointmentType === AppointmentTypeStrings.MOBILE
                || this.selectedAppointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP)
                && serviceLocationToUse.mobileProviderNumber);
            const validInShopAppointmentType = ((this.selectedAppointmentType === AppointmentTypeStrings.IN_SHOP
                || this.selectedAppointmentType === AppointmentTypeStrings.DROP_OFF)
                && (this.selectedProvider?.providerNumber || serviceLocationToUse.provider?.providerNumber));

            const serviceLocationPreReqs = serviceLocationToUse.zipCode !== null
                && serviceLocationToUse.zipCodeCtu !== null
                && serviceLocationToUse.appointmentType !== null
                && (validMobileAppointmentType || validInShopAppointmentType)
                && !this.isDatePickerRefreshing;

            const damageInfo = useMainStore().order.damage.isRepair
                || (useMainStore().order.lineItems?.glassParts != null && useMainStore().order.lineItems.glassParts.length > 0);

            const supportingItems = this.supportingItems !== null;

            return (serviceLocationPreReqs && supportingItems && damageInfo);
        },
        isFormValid() {
            const hasTimeSlotSelected = this.selectedTimeSlotInfo?.timeSlot?.routeCode != null;
            return hasTimeSlotSelected;
        },
        navigateBackScenario() {
            const { isNoComp, isITAC } = useMainStore();
            return isNoComp || isITAC
                ? this.navigationScenarios.CLICKED_BACK_CANNOT_REACH_TPA_FLOW
                : this.navigationScenarios.CLICKED_BACK_CAN_REACH_TPA_FLOW;
        },
        supportingItems() {
            return useMainStore().lineItems.supportingItems;
        }
    },
    watch: {
        inShopDatesData(newData) {
            if (newData?.initialShopTimeSlotsResponse?.days?.length > 0) {
                const numberOfDaysNeededToBeHighAvailability = 2;
                const availabilityEndDate = new Date();
                availabilityEndDate.setDate(availabilityEndDate.getDate() + 6);
                
                const datesInAvailabilityRange = newData.initialShopTimeSlotsResponse.days.filter((day) => {
                    const dayDate = new Date(`${day.date}T00:00:00`);
                    return dayDate <= availabilityEndDate;
                });
                const isGoodAvailability =
                    datesInAvailabilityRange.filter((x) => x.timeSlots.length > 0).length
                    >= numberOfDaysNeededToBeHighAvailability;

                this.inShopAvailabilityRating = isGoodAvailability ? 'high' : 'low';
            } else {
                this.inShopAvailabilityRating = 'low';
            }
        }
    },
    mounted() {
        showIssLoadingModal(true);
        this.mql = window.matchMedia('(min-width: 1200px)');
        this.isMobileView = !this.mql.matches;
        this.mql.addEventListener('change', this.handleMqlChange);
    },
    unmounted() {
        if (this.mql) {
            this.mql.removeEventListener('change', this.handleMqlChange);
        }
    },
    methods: {
        splitCopyOnCMSPlaceHolder,
        arePagePrerequisitesValid() {
            return useMainStore().order.serviceLocation.zipCode !== null;
        },
        async autoSelectTimeslotConfirmed(emittedValue) {
            if (this.mainStore.isNoComp || this.mainStore.isITAC) {
                console.log('User is No Comp or ITAC, skipping mobile fee update on auto select timeslot confirmed');
                // this.mainStore.updateMobileFee(this.mobileFeePart);
            }

            const providerToUse = {
                providerNumber: emittedValue.mobileProviderNumber,
                address: {
                    streetAddress: null,
                    city: null,
                    state: null,
                    zipCode: null,
                    zipCodeCtu: null
                }
            };

            this.mainStore.updateServiceLocation({
                state: emittedValue.zipCodeData.state,
                zipCode: emittedValue.zipCodeData.zipCode,
                zipCodeCtu: emittedValue.zipCodeData.zipCodeCtu,
                appointmentType: AppointmentTypeStrings.MOBILE,
                provider: providerToUse
            });

            const timeSlotToUse = {
                date: emittedValue.date,
                routeCode: emittedValue.timeSlot.id,
                startTime: emittedValue.timeSlot.startTime,
                endTime: emittedValue.timeSlot.endTime,
                jobMaxMinutes: emittedValue.estimatedServiceMinutesMax.toString(),
                jobMinMinutes: emittedValue.estimatedServiceMinutesMin.toString(),
            };

            this.mainStore.saveSchedule(timeSlotToUse);
            showIssLoadingModal(true);
            this.$router.navigate(
                this.navigationScenarios.CLICKED_FORWARD,
                this.$route
            );
        },
        async checkMobileFirstExperience(mobileFirstObject = {}) {
            const mobileFirstExperimentVariation = this.getExperimentVariationNameByTestName(experimentTest.ISS_MOBILE_FIRST_POPUP_V3);
            const isMobileFirstTestVariation = mobileFirstExperimentVariation === experimentVariation.ISS_MOBILE_FIRST_TEST_V3;
            const showMobileFirst = this.getSettingValue(experimentSettings.ISS_MOBILE_FIRST_SHOW_FIRST_MOBILE_APPOINTMENT);
            if (showMobileFirst) {
                const pmMobileDaysLimit = this.getSettingValue(experimentSettings.ISS_MOBILE_FIRST_MAX_PM_MOBILE_DAYS);
                const mobileDaysLimit = this.getSettingValue(experimentSettings.ISS_MOBILE_FIRST_MAX_MOBILE_DAYS);
                const hasSelectedDate = !!this.getSelectedDate();
                const isServiceableMobile = isServiceableMobileWithData(
                    mobileFirstObject.serviceabilityDetails?.isGlassServiceableMobile ?? null,
                    mobileFirstObject.serviceabilityDetails?.isRecalibrationServiceableMobile ?? null
                );
                if (!hasSelectedDate && isServiceableMobile && mobileFirstObject.mobileProviderNumber && mobileFirstObject.zipCode) {
                    const todayDateObject = new Date();
                    const todayDateString = convertDateToDateString(todayDateObject);
                    const calendarViewDirection = 'future';
                    const initialDays = 15;

                    const initialViewStartDate = todayDateString;
                    const initialEndDate = new Date();
                    initialEndDate.setDate(initialEndDate.getDate() + (initialDays - 1));
                    const initialViewEndDate = convertDateToDateString(initialEndDate);
                    const preSelectedDate = this.selectedDate;

                    const initialData = await getAvailableDates(
                        initialViewStartDate,
                        initialViewEndDate,
                        AppointmentTypeStrings.MOBILE,
                        mobileFirstObject.mobileProviderNumber,
                        mobileFirstObject.zipCode
                    ).then((response) => ({
                        todayDate: todayDateString,
                        initialViewStartDate,
                        initialViewEndDate,
                        calendarViewDirection,
                        initialShopTimeSlotsResponse: response,
                        preSelectedDate,
                        initialDaysLoaded: initialDays,
                        daysFromStart: null
                    }))
                    .catch(() => {
                        return {
                            todayDate: todayDateString,
                            initialViewStartDate,
                            initialViewEndDate,
                            calendarViewDirection,
                            initialShopTimeSlotsResponse: { days: [] },
                            preSelectedDate,
                            initialDaysLoaded: initialDays,
                            daysFromStart: null
                        };
                    });
                    
                    this.mobileDatesData = initialData;

                    const estimatedServiceMinutesMax = initialData.initialShopTimeSlotsResponse?.estimatedServiceMinutesMaximum || 120;
                    const estimatedServiceMinutesMin = initialData.initialShopTimeSlotsResponse?.estimatedServiceMinutesMinimum || 90;

                    const retTimeSlotsResponse = [];
                    initialData.initialShopTimeSlotsResponse.days.forEach((selectableDate) => {
                        const dateObjectToPush = {
                            date: selectableDate.date,
                            timeSlots: selectableDate.timeSlots,
                            morningTimeSlots: selectableDate.timeSlots.filter((timeSlot) => {
                                const timeHour = parseInt(timeSlot.startTime.split(':')[0], 10);
                                return timeHour < 12;
                            }).map((timeSlot) => mapTimeSlot(timeSlot, 'morning')),
                            afternoonTimeSlots: selectableDate.timeSlots.filter((timeSlot) => {
                                const timeHour = parseInt(timeSlot.startTime.split(':')[0], 10);
                                return timeHour >= 12;
                            }).map((timeSlot) => mapTimeSlot(timeSlot, 'afternoon')),
                            isSelected: false
                        };

                        if (dateObjectToPush.morningTimeSlots.length > 0) {
                            const findIndex = dateObjectToPush.morningTimeSlots.findIndex((timeSlot) => timeSlot.id.endsWith('DROP OFF'));
                            if (findIndex !== -1) {
                                const dropOffSlot = dateObjectToPush.morningTimeSlots.splice(findIndex, 1)[0];
                                dateObjectToPush.morningTimeSlots.unshift(dropOffSlot);
                            }
                        }
                        if (dateObjectToPush.afternoonTimeSlots.length > 0) {
                            const findIndex = dateObjectToPush.afternoonTimeSlots.findIndex((timeSlot) => timeSlot.id.endsWith('DROP OFF'));
                            if (findIndex !== -1) {
                                const dropOffSlot = dateObjectToPush.afternoonTimeSlots.splice(findIndex, 1)[0];
                                dateObjectToPush.afternoonTimeSlots.push(dropOffSlot);
                            }
                        }
                        retTimeSlotsResponse.push(dateObjectToPush);
                    });

                    let dateDifferenceForPmMobile = null;
                    const firstPmMobileDateWithTimeSlots = retTimeSlotsResponse.find((date) => {
                        const hasPmMobileTimeSlots = date.afternoonTimeSlots?.length > 0;
                        if (hasPmMobileTimeSlots && pmMobileDaysLimit) {
                            dateDifferenceForPmMobile = calcDaysBetweenDates(todayDateString, date.date);
                            return dateDifferenceForPmMobile <= pmMobileDaysLimit;
                        }
                        return hasPmMobileTimeSlots;
                    });

                    let dateDifferenceForMobile = null;
                    const firstMobileDateWithTimeSlots = retTimeSlotsResponse.find((date) => {
                        const hasMobileTimeSlots = date.morningTimeSlots?.length > 0;
                        const hasPmMobileTimeSlots = date.afternoonTimeSlots?.length > 0;
                        if (hasMobileTimeSlots || hasPmMobileTimeSlots) {
                            if (mobileDaysLimit) {
                                dateDifferenceForMobile = calcDaysBetweenDates(todayDateString, date.date);
                                return mobileDaysLimit && dateDifferenceForMobile <= mobileDaysLimit;
                            }
                            return true;
                        }
                        return hasPmMobileTimeSlots;
                    });

                    const zipCodeData = await getMobileZipCodeData(mobileFirstObject.zipCode);
                    if ((firstPmMobileDateWithTimeSlots || firstMobileDateWithTimeSlots) && zipCodeData?.isValid) {
                        zipCodeData.zipCode = mobileFirstObject.zipCode;
                        const timeSlotForAutoSelectionMobile = {
                            date: firstPmMobileDateWithTimeSlots ? firstPmMobileDateWithTimeSlots.date : firstMobileDateWithTimeSlots.date,
                            estimatedServiceMinutesMax,
                            estimatedServiceMinutesMin,
                            isRepair: this.mainStore.order.damage.isRepair,
                            mobileProviderNumber: mobileFirstObject.mobileProviderNumber,
                            timeSlot: firstPmMobileDateWithTimeSlots ? firstPmMobileDateWithTimeSlots.afternoonTimeSlots[0] 
                                        : (firstMobileDateWithTimeSlots.morningTimeSlots[0] || firstMobileDateWithTimeSlots.afternoonTimeSlots[0]),
                            zipCodeData
                        };

                        const dateObjectToUse = new Date(`${timeSlotForAutoSelectionMobile.date}T${timeSlotForAutoSelectionMobile.timeSlot.startTime}:00`);
                        timeSlotForAutoSelectionMobile.dateObject = dateObjectToUse;
                        timeSlotForAutoSelectionMobile.dayOfWeek = dateObjectToUse.toLocaleDateString('en-US', { weekday: 'long' });

                        const experiment = this.getExperimentByName(experimentUniverses.ISS_MOBILE_FIRST_APPOINTMENTS);
                        if (experiment && !experiment.isExposed) {
                            this.mainStore.logMobileFirstExperimentExposure();
                        }

                        if (isMobileFirstTestVariation) {
                            this.$refs[SUGGEST_TIMESLOT_MODAL_REF_NAME].openModal(timeSlotForAutoSelectionMobile);
                        } else {
                            console.log('In Control group or experiment not found, skip showing popup');
                        }                        
                    }                    
                }
            }
        },
        async setData(premiumFeeWithPriceResponse, initialServiceLocationObj) {
            this.selectedServiceLocation = initialServiceLocationObj;
            this.mobilePremiumAppointmentFee = premiumFeeWithPriceResponse
                ? premiumFeeWithPriceResponse[0]
                : null;

            if (initialServiceLocationObj?.zipCodeCtu) {
                this.$refs.locationAlerts.loadInitialData(
                    initialServiceLocationObj.zipCodeCtu,
                    initialServiceLocationObj.provider?.ctu
                ).then((alertReasons) => {
                    this.$refs.locationAlerts.initializeComponent(alertReasons.data);
                });
            }

            if (this.selectedAppointmentType !== AppointmentTypeStrings.MOBILE
                && this.selectedAppointmentType !== AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP) {
                await this.getDatePickerInitialData(initialServiceLocationObj.provider?.providerNumber).then((initialData) => {
                    this.selectableDatesData = initialData.initialShopTimeSlotsResponse;
                    this.$refs.datePicker.setCalendarData(initialData);
                });
            } else {
                this.mobileProviderNumber = initialServiceLocationObj.mobileProviderNumber;
                this.selectedMobileZipCode = initialServiceLocationObj.zipCode;
                await this.getDatePickerInitialData().then((initialData) => {
                    this.selectableDatesData = initialData.initialShopTimeSlotsResponse;
                    this.$refs.datePicker.setCalendarData(initialData);
                });
            }
        },
        appointmentTypeChangedFromServiceLocation(newAppointmentType) {
            this.selectedAppointmentType = newAppointmentType.appointmentType;
            if (newAppointmentType.appointmentType === AppointmentTypeStrings.IN_SHOP) {
                if (this.inShopDatesData?.initialShopTimeSlotsResponse?.days?.length > 0) {
                    this.selectableDatesData = this.inShopDatesData.initialShopTimeSlotsResponse;
                    this.$refs.datePicker.initializeComponent(this.inShopDatesData);
                }
            } else if (this.mobileDatesData?.initialShopTimeSlotsResponse?.days?.length > 0) {
                this.selectableDatesData = this.mobileDatesData.initialShopTimeSlotsResponse;
                this.$refs.datePicker.initializeComponent(this.mobileDatesData);
            }
        },
        cityUpdatedFromServiceLocation(newCity) {
            this.selectedServiceLocationCity = newCity;
        },
        clearMobileDataFromServiceLocation() {
            if (this.selectedServiceLocation) {
                this.selectedServiceLocation.mobileProviderNumber = null;
            }
            this.mobileDatesData = [];
            this.mobileProviderNumber = null;
            this.selectedMobileZipCode = null;
         },
        dateSelectedFromPicker(date) {
            this.selectedDate = date;
            this.showDatePickerError = false;
        },
        getAppointmentType() {
            return this.mainStore.order?.serviceLocation?.appointmentType;
        },
        async getAvailableDatesMethod(startDate, endDate) {
            let mobileProviderNumberToUse = this.mobileProviderNumber;
            if (this.selectedAppointmentType === AppointmentTypeStrings.MOBILE
                || this.selectedAppointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP) {
                mobileProviderNumberToUse = this.selectedServiceLocation.mobileProviderNumber;
            }

            const newShopTimeSlots = await getAvailableDates(
                startDate,
                endDate,
                this.selectedAppointmentType,
                this.selectedProvider.providerNumber || mobileProviderNumberToUse,
                this.selectedMobileZipCode
            );
            // ADD API CALL RESULTS TO EXISTING DATE DATA
            this.selectableDatesData.days =
                this.selectableDatesData.days.concat(newShopTimeSlots.days);
            return newShopTimeSlots;
        },
        getAvailableDates,
        async getDatePickerInitialData(defaultProviderNumber = null) {
            let todayDateString;
            const todayDateObject = new Date();
            const calendarViewDirection = 'future';
            const initialDays = 15;

            if (this.todayString) {
                todayDateString = this.todayString;
            } else {
                todayDateString = convertDateToDateString(todayDateObject);
            }

            const initialViewStartDate = todayDateString;
            const initialEndDate = new Date();
            initialEndDate.setDate(initialEndDate.getDate() + (initialDays - 1));
            let initialViewEndDate = convertDateToDateString(initialEndDate);
            const preSelectedDate = this.selectedDate;

            const endDateObject = this.getEndDateForExistingDate(
                todayDateObject,
                preSelectedDate,
                initialDays
            );

            if (endDateObject.endDateString !== initialViewEndDate) {
                initialViewEndDate = endDateObject.endDateString;
            }

            let mobileProviderNumberToUse = defaultProviderNumber;
            if (this.selectedAppointmentType === AppointmentTypeStrings.MOBILE
                || this.selectedAppointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP) {
                mobileProviderNumberToUse = this.selectedServiceLocation.mobileProviderNumber;
            }

            const initialData = await getAvailableDates(
                initialViewStartDate,
                initialViewEndDate,
                this.selectedAppointmentType || AppointmentTypeStrings.IN_SHOP,
                this.selectedProvider?.providerNumber || mobileProviderNumberToUse,
                this.selectedServiceLocation.zipCode
            ).then((response) => ({
                todayDate: todayDateString,
                initialViewStartDate,
                initialViewEndDate,
                calendarViewDirection,
                initialShopTimeSlotsResponse: response,
                preSelectedDate,
                initialDaysLoaded: endDateObject.newDaysLoaded || initialDays,
                daysFromStart: endDateObject.daysFromStart || null
            }))
            .catch(() => {
                return {
                    todayDate: todayDateString,
                    initialViewStartDate,
                    initialViewEndDate,
                    calendarViewDirection,
                    initialShopTimeSlotsResponse: { days: [] },
                    preSelectedDate,
                    initialDaysLoaded: endDateObject.newDaysLoaded || initialDays,
                    daysFromStart: endDateObject.daysFromStart || null
                };
            });

            if (this.selectedAppointmentType === AppointmentTypeStrings.MOBILE
                || this.selectedAppointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP) {
                this.mobileDatesData = initialData;

                if (this.selectedProvider?.providerNumber) {
                    const inShopData = await getAvailableDates(
                        initialViewStartDate,
                        initialViewEndDate,
                        AppointmentTypeStrings.IN_SHOP,
                        this.selectedProvider?.providerNumber || defaultProviderNumber,
                        this.selectedServiceLocation.zipCode
                    ).then((response) => ({
                        todayDate: todayDateString,
                        initialViewStartDate,
                        initialViewEndDate,
                        calendarViewDirection,
                        initialShopTimeSlotsResponse: response,
                        preSelectedDate,
                        initialDaysLoaded: endDateObject.newDaysLoaded || initialDays,
                        daysFromStart: endDateObject.daysFromStart || null
                    }));

                    this.inShopDatesData = inShopData;
                }
            } else {
                this.inShopDatesData = initialData;
                this.mobileDatesData = [];
            }

            return initialData;
        },
        getEndDateForExistingDate(startDate, selectedDateString, daysInView) {
            const endDate = new Date(startDate);
            endDate.setDate(endDate.getDate() + (daysInView - 1));

            if (selectedDateString) {
                const selectedDate = new Date(`${selectedDateString}T00:00:00`);
                const daysDifferenceComparedToStartDate = Math.ceil((selectedDate - startDate) / (1000 * 60 * 60 * 24));
                if (selectedDate > endDate) {
                    const daysDifferenceComparedToStartDateAsPages = Math.ceil(daysDifferenceComparedToStartDate / daysInView);
                    const newEndDate = new Date(startDate);
                    newEndDate.setDate(newEndDate.getDate() + (daysDifferenceComparedToStartDateAsPages * daysInView) - 1);

                    return {
                        endDateString: convertDateToDateString(newEndDate),
                        newDaysLoaded: (daysDifferenceComparedToStartDateAsPages * daysInView),
                        daysFromStart: daysDifferenceComparedToStartDate
                    };
                }

                return {
                    endDateString: convertDateToDateString(endDate),
                    newDaysLoaded: null,
                    daysFromStart: daysDifferenceComparedToStartDate
                };
            }

            return {
                endDateString: convertDateToDateString(endDate),
                newDaysLoaded: null,
                daysFromStart: null
            };
        },
        getServiceZipCtuCodeFromStore() {
            return this.mainStore.order.serviceLocation.zipCodeCtu;
        },
        getSelectedDate() {
            return this.mainStore.order.schedule.date;
        },
        getSelectedProvider() {
            return this.mainStore.order.serviceLocation.provider;
        },
        getSelectedTimeSlotInfo() {
            const isPremiumAppointment =
                !!(
                    this.supportingItems?.filter((lineItem) =>
                        lineItem.partType === PREMIUM_FEE_PART_TYPE) ?? []
                ).length > 0;

            const selectedTimeSlotInfo = {
                timeSlot: this.mainStore.order.schedule,
                isPremiumAppointment
            };

            return selectedTimeSlotInfo;
        },
        getServiceLocation() {
            return this.mainStore.order.serviceLocation;
        },
        getServiceLocationCity() {
            return this.mainStore.order.serviceLocation?.city;
        },
        handleMqlChange(e) {
            this.isMobileView = !e.matches;
        },
        inShopZipUpdatedFromServiceLocation(inShopZipServiceLocation) {
            if (inShopZipServiceLocation) {
                this.mobileProviderNumber = null;
                this.selectedMobileZipCode = null;
                this.selectedServiceLocation = inShopZipServiceLocation;
            }
        },
        mobileZipUpdatedFromServiceLocation(mobileZipServiceLocation) {
            if (mobileZipServiceLocation) {
                this.mobileProviderNumber = mobileZipServiceLocation.mobileProviderNumber;
                this.selectedMobileZipCode = mobileZipServiceLocation.zipCode;
                this.selectedServiceLocation = mobileZipServiceLocation;

                if (mobileZipServiceLocation.refreshDatePicker) {
                    this.refreshDatePicker();
                }
            }
        },
        async providerChangedFromServiceLocation(newProvider) {
            this.selectedProvider = newProvider?.provider;
            if (newProvider?.refreshDatePicker && newProvider.provider) {
                this.mainStore.updateServiceLocationProvider(newProvider.provider);

                showIssLoadingModal(true);
                await this.mainStore.getBillToInfo(newProvider.provider?.providerNumber)
                    .then(() => {
                        this.refreshDatePicker();
                    })
                    .catch(() => {
                        console.warn('Error fetching bill to info...');
                        showIssLoadingModal(false);
                    });
            }
        },
        async refreshDatePicker() {
            this.resetLocalFlags();
            this.isDatePickerRefreshing = true;
            await this.getDatePickerInitialData().then((data) => {
                this.selectableDatesData = data.initialShopTimeSlotsResponse;
                this.$refs.datePicker.initializeComponent(data);
                this.isDatePickerRefreshing = false;
                showIssLoadingModal(false);
            });
        },
        resetLocalFlags() {
            this.selectedDate = null;
            this.selectedTimeSlotInfo = null;
            this.showDatePickerError = false;
        },
        timeSlotSelectedFromPicker(timeSlot) {
            this.selectedTimeSlotInfo = timeSlot;
            this.showDatePickerError = false;
        },
        async forwardButtonAction() {
            if (!this.isFormValid) {
                this.showDatePickerError = true;
                return;
            }

            let appointmentTypeToUse = this.selectedAppointmentType;
            if (appointmentTypeToUse === AppointmentTypeStrings.IN_SHOP && this.selectedTimeSlotInfo.timeSlot?.isDropoff === true) {
                appointmentTypeToUse = AppointmentTypeStrings.DROP_OFF;
            }

            await this.$refs.serviceLocation.forwardButtonAction(appointmentTypeToUse);
            this.mainStore.saveSchedule(this.selectedTimeSlotInfo.timeSlot);
            this.$router.navigate(
                this.navigationScenarios.CLICKED_FORWARD,
                this.$route
            );
        }
    }
};
</script>

<style lang="scss" scoped>
$page-side-padding: 1.5rem;

.iss-heritage-container-width {
    padding-right: 0.9375rem;
    padding-left: 0.9375rem;

    .schedule-page-container {
        position: relative;
        min-height: 1px;
    }
}

:deep(.text-link-small) {
    a,
    .btn-link {
        font-size: 0.875rem;
        line-height: 1.5;
    }
}

:deep(.change-shop-link) {
    a {
        font-weight: 500;
    }
}

:deep(.subheader-primary) {
    h5.dark-header {
        margin-bottom: 0.25rem !important;
    }
}
</style>
