<template>
    <Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm">
        <loadingModal ref="loadingModal" />
        <funnelHeader cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" />
        <mobileFirstModal
            modalWidgetName="MobileFirstModalWidget"
            ref="mobileFirstModal"
            @confirm-appointment="updateTimeSlotandNavigateForward" />
        <div
            class="container page-container-grouped-styles"
            :class="[isMobileFirstModalOpen ? 'hidden-background' : '']">
            <div class="row">
                <div class="col-12 col-md-10 col-lg-8 col-xl-7">
                    <mobileFeeWaiverAlert
                        cmsWidgetName="MobileFeeFreeDropdownWidget"
                        v-if="showMobileFreeAlert" />
                </div>
            </div>
            <div class="row appointment-type">
                <div class="col-12 col-md-10 col-lg-8 col-xl-7">
                    <funnelSubHeader
                        cmsWidgetName="ScheduleYourServiceWidget"
                        id="schedule-your-service" />
                    <appointmentTypeQuestion
                        v-model="appointmentTypeFromAppointmentTypeQuestion"
                        v-show="isAppointmentTypeDisplayed"
                        :isServiceableMobile="isServiceableMobile"
                        :isServiceableInshop="isServiceableInshop"
                        :isDisplayed="isAppointmentTypeDisplayed"
                        :mobileFeeApplies="mobileFeeApplies"
                        :zipCode="zipCode"
                        ref="appointmentTypeQuestion"
                        groupName="appointmentTypeQuestion"
                        cmsWidgetName="AppointmentTypeQuestionWidget"
                        validationRules="option-required"
                        labelBold="true" />
                </div>
            </div>
            <div class="row">
                <div class="col-12 col-md-10 col-lg-8 col-xl-7">
                    <alert
                        ref="alertMobileOnly"
                        class="mt-5 mb-5"
                        cmsWidgetName="AlertMobileOnlyWidget"
                        v-if="displayServiceableMobileOnly"
                        alertClass="alert-warning" />
                    <alert
                        ref="alertRecalNoMobile"
                        class="mb-5"
                        cmsWidgetName="AlertRecalNoMobileWidget"
                        v-if="displayRecalibrationWarning"
                        @text-link-clicked="openModalAction"
                        alertClass="alert-warning" />
                    <alert
                        ref="alertInshopOnly"
                        class="mt-5 mb-5"
                        cmsWidgetName="AlertInshopOnlyWidget"
                        v-if="displayServiceableInshopOnly"
                        alertClass="alert-warning" />
                    <alert
                        ref="alertMilitaryBaseZip"
                        class="mt-5 mb-5"
                        cmsWidgetName="AlertMilitaryBaseZipWidget"
                        v-if="displayMilitaryZipAlert"
                        alertClass="alert-warning" />
                    <alert
                        ref="alertNoShops"
                        class="mt-5 mb-5"
                        cmsWidgetName="AlertNoShopsWidget"
                        v-if="displayNoShopsAlert"
                        alertClass="alert-warning" />
                </div>
            </div>
            <div
                v-if="appointmentType && appointmentType === appointmentTypeStrings.MOBILE"
                class="col-12 col-md-10 col-lg-8 col-xl-7">
                <funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" class="mt-4" />
                <serviceZipModalQuestion
                    editScreenReaderTextCmsWidgetName="ScreenReaderZipEditWidget"
                    v-model="serviceZipCodeQuestion"
                    ref="serviceZipCodeQuestion"
                    :carId="carId"
                    :isVehicleHeavyTruck="isVehicleHeavyTruck"
                    :mobileFeePart="mobileFeePart"
                    @updated-mobile-fee-part="setMobileFeePart"
                    @updated-recycle-fee-part="setRecycleFeePart"
                    @updated-serviceability="setServiceabilityDetails"
                    @updated-contains-military-base="setContainsMilitaryBase"
                    @updated-bill-to-account-number="setBillToAccountNumber"
                    @service-zip-changed-from-modal="onServiceZipChanged"
                    linkWidgetName="ServiceZipLinkWidget"
                    modalWidgetName="ServiceZipModalWidget" />
            </div>
            <div
                class="row your-shop-location"
                v-if="appointmentType && appointmentType !== appointmentTypeStrings.MOBILE">
                <div class="col-12 col-md-10 col-lg-8 col-xl-7">
                    <div>
                        <shopLocation
                            v-if="
                                appointmentType && appointmentType !== appointmentTypeStrings.MOBILE
                            "
                            :selectedShop="selectedShopAnswer"
                            :selectedProviderNumberFromParent="selectedProvider?.providerNumber"
                            :shopProviderDataFromParent="shopProviderData"
                            :zipCodeFromParent="zipCode"
                            :isShopQuestionDisplayed="isShopQuestionDisplayed"
                            @shop-selected="onShopSelected"
                            @updated-serviceability="setServiceabilityDetails" />
                    </div>
                    <div>
                        <textBlock
                            v-if="mobileFeeApplies && isMobileSelected"
                            :customText="mobileFeeText"
                            cmsWidgetName="MobileFeeDisclaimerWidget"
                            typeStyle="caption"
                            class="ps-4 pe-4 mt-4" />
                    </div>

                    <contentGroupModal ref="RecalModal" cmsWidgetName="RecalModal" />
                </div>
            </div>
            <div class="row date-picker-wrapper">
                <div class="col-12 col-md-10 col-lg-8 col-xl-7">
                    <locationAlerts cmsWidgetPrefix="LocationAlert-" ref="locationAlerts" />
                    <div v-show="appointmentType" class="date-picker-header fw-normal mt-5 mb-5">
                        <textBlock :customText="datePickerHeaderText" typeStyle="button-question" />
                        <durationTextBlock
                            :isSameDay="isSameDay"
                            :appointmentType="appointmentType"
                            :estimatedServiceMinutesMinimum="estimatedServiceMinutesMinimum"
                            :estimatedServiceMinutesMaximum="estimatedServiceMinutesMaximum"
                            :isOvernightDropoff="isOvernightDropoff" />
                    </div>
                    <datePicker
                        :currentZip="zipCode"
                        :currentProviderNumber="selectedProvider?.providerNumber"
                        v-show="appointmentType"
                        customComponentId="dateQuestion"
                        selectableDatesSetting="custom"
                        ref="datePicker"
                        v-model="selectedDate"
                        :isMobileSelected="isMobileSelected"
                        class="text-link-small"
                        :getMoreDatesCallback="getMoreScheduleData"
                        validationRules="date-required"
                        @date-clicked="handleDateClicked"
                        :pricingByDayBasePrice="pricingByDayBasePrice"
                        :pricingByDayUpcharge="pricingByDayUpcharge"
                        :showPricingByDay="showPricingByDay"
                        :isPricingByDayExperiment="isPricingByDayExperiment" />
                    <timeSlotQuestion
                        ref="timeSlotModalQuestion"
                        v-if="showTimeSlotQuestion"
                        @time-slot-selection-changed="updateTimeSlot"
                        waitListLabelWidget="WaitListLabelWidget"
                        waitListQuestionWidget="WaitListQuestionWidget"
                        mobilePremiumCmsWidgetName="MobilePremiumTimeSlotModal"
                        mobileCmsWidgetName="MobileTimeSlotModal"
                        dropoffCmsWidgetName="DropOffTimeSlotModal"
                        sameDayDropOffCmsWidgetName="SameDayDropOffTimeSlotModal"
                        overnightDropOffCmsWidgetName="OvernightDropOffTimeSlotModal"
                        dropOffOrPickATimeQuestionCmsWidgetName="DropOffOrPickATimeQuestionWidget"
                        :appointmentType="appointmentType"
                        :premiumAppointmentFee="mobilePremiumAppointmentFee"
                        :displayWaitList="displayWaitList"
                        :timeSlotsForSelectedDate="timeSlotsForSelectedDate"
                        :isSameDay="isSameDay"
                        :selectedRouteCodeData="selectedRouteCodeData"
                        @waitListRequested="handleWaitListRequested" />
                    <navbar
                        cmsWidgetName="FunnelFooterWidget"
                        ref="navbar"
                        :isForwardActionDisabled="isForwardActionDisabled"
                        @back-clicked="backButtonAction"
                        @ForwardClicked="forwardButtonAction" />
                </div>
            </div>
        </div>
    </Form>
</template>

<script>
// Components
import alert from "@/ux-components/alert/alert";
import serviceZipModalQuestion from "@/layouts/service-location/service-zip-modal-question/service-zip-modal-question";
import appointmentTypeQuestion from "@/layouts/service-location/appointment-type-question/appointment-type-question";
import shopListButton from "@/layouts/service-location/shop-question/shop-list-button/shop-list-button";
import shopLocation from "@/layouts/schedule/shop-location/shop-location";
import timeSlotQuestion from "@/layouts/schedule/time-slot-question/time-slot-question.vue";
import durationTextBlock from "@/layouts/schedule/duration-text-block/duration-text-block.vue";
import mobileFirstModal from "@/layouts/schedule/mobile-first-modal/mobile-first-modal.vue";

import shopQuestion from "@/layouts/service-location/shop-question/shop-question";
import shopQuestionPopup from "@/layouts/service-location/shop-question/shop-question-popup";
import buttonQuestion from "@/digital-components/button-question/button-question.vue";

import funnelHeader from "@/fmg-components/funnel-header/funnel-header";
import navbar from "@/fmg-components/nav-bar/nav-bar";
import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header";
import loadingModal from "@/fmg-components/loading-modal/loading-modal.vue";
import { Form, defineRule } from "vee-validate";
import { errorMessages } from "@/constants/error-messages";
import datePicker from "@/digital-components/date-picker/date-picker";
import locationAlerts from "@/layouts/schedule/location-alerts/location-alerts";
import contentGroupModal from "@/fmg-components/content-group-modal/content-group-modal";
import textBlock from "@/digital-components/text-block/text-block";
import mobileFeeWaiverAlert from "./mobile-fee-waiver-alert/mobile-fee-waiver-alert.vue";

// Supporting files
import baseMixin from "@/mixins/base-mixin.js";
import experimentMixin from "@/mixins/experiment-mixin.js";
import { experimentUniverses, experimentSettings } from "@/constants/experiments";
import {
    AppointmentTypeStrings,
    RouteCodeFlags,
    PREMIUM_FEE_PART_TYPE,
    PRICING_BY_DAY_PART_TYPE,
} from "@/constants/schedule-constants";

import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { settleAllPromises } from "@/helpers/layout-helper";
import {
    getPricedMobileFeePart,
    getServiceabilityDetails,
    getShopProviderData,
    getZipCodeData,
} from "@/layouts/service-location/helpers/service-location-helper/service-location-helper";
import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
import { applicationConfig } from "@/constants/application-config";
import { Provider } from "@/layouts/service-location/classes/provider";
import { partNumberStrings } from "@/constants/part-number-strings";

import store from "@/store";

import { storeActions } from "@/constants/store-actions";
import { splitCopyOnCMSPlaceHolder } from "@/helpers/cms-content-helper";
import {
    calcDaysBetweenDates,
    convertDateStringToDate,
    sumDateString,
    isDropOffRouteCode,
    getTodayDate,
} from "@/layouts/schedule/helpers/schedule-helper";

import { DAYS_OF_WEEK } from "@/digital-components/date-picker/mixins/constants";
import { required } from "@/helpers/validation-rules";
import { getAmountDue, getPricingByDayPartWithPrice } from "@/helpers/pricing-helper.js";
import { getItemsWithoutRecalParts } from "@/helpers/recal-helper";
import { deepClone } from "@/helpers/object-helper";
import { debugLog } from "@/helpers/debug-log-helper";
import {
    getSessionKeyValue,
    getUserIdValue,
    getDeviceIdValue,
} from "@/helpers/heritage-integration/cookie-helper";

// DEFINE VALIDATION RULES
defineRule("mobile-location-required", (value) => {
    const addressQuestionsValues = Object.values(
        [
            value.addressQuestions.streetAddress,
            value.addressQuestions.city,
            value.isVehicleProtected,
        ] || {}
    );
    const filledFields = addressQuestionsValues.filter(
        (val) => val !== null && val !== undefined && val !== ""
    );
    if (
        value.isMobileSelected &&
        filledFields.length > 0 &&
        filledFields.length < addressQuestionsValues.length
    ) {
        return errorMessages.MOBILE_LOCATION_REQUIRED;
    }
    return true;
});
defineRule("date-required", required(errorMessages.DATE_REQUIRED));

// Define constants
const TIME_SLOTS_CALL_DAYS_LIMIT = 34; // needs to be 34 for API limits (35 does not consistently work)
const NUMBER_OF_CALENDAR_ROWS_TO_SHOW_FOR_INITIAL_VIEW = 2;
const MOBILE_FEE_PART_TYPE = "MOBILE FEE";

const getScheduleApiResponse = async ({
    startDateString,
    endDateString,
    providerNumber,
    zipCode,
    includeMobileTimeSlots = true,
    includeInshopTimeSlots = true,
}) => {
    const apiEndDateLimit = sumDateString(startDateString, TIME_SLOTS_CALL_DAYS_LIMIT);
    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 storeActionConfigInshop;
        let storeActionConfigMobile;

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

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

        storeActionConfigMobile = {
            storeAction: storeActions.GET_MOBILE_TIME_SLOTS,
            payload: {
                startDate: apiStartDate,
                endDate: apiEndDate,
                zipCode: zipCode,
            },
        };
        storeActionConfigInshop = {
            storeAction: storeActions.GET_SHOP_TIME_SLOTS,
            payload: {
                startDate: apiStartDate,
                endDate: apiEndDate,
                shopAppointmentType: "InshopOrDropoff",
                providerNumber: providerNumber,
            },
        };
        if (apiStartDate < apiEndDate) {
            if (includeInshopTimeSlots) storeActionConfigs.push(storeActionConfigInshop);
            if (includeMobileTimeSlots) storeActionConfigs.push(storeActionConfigMobile);
        }
    }

    const inshopTimeSlotsData = {
        days: [],
    };
    const mobileTimeSlotsData = {
        days: [],
    };
    function compareDayStrings(a, b) {
        if (a.date < b.date) return -1;
        if (a.date > b.date) return 1;
        return 0;
    }
    function removePastDates(array, todaysDate) {
        return array.filter(function (a) {
            return !(a.date < todaysDate);
        });
    }

    const makeParallelCalls = async () => {
        await Promise.all(
            storeActionConfigs.map(async (storeActionConfig) => {
                if (storeActionConfig.storeAction.indexOf("Mobile") > -1) {
                    const mobileTimeSlotsResponse =
                        await baseMixin.methods.dispatchStoreActionWithLogging(
                            storeActionConfig.storeAction,
                            storeActionConfig.payload,
                            "schedule",
                            false
                        );
                    mobileTimeSlotsData.estimatedServiceMinutesMinimum =
                        mobileTimeSlotsResponse.data.estimatedServiceMinutesMinimum;
                    mobileTimeSlotsData.estimatedServiceMinutesMaximum =
                        mobileTimeSlotsResponse.data.estimatedServiceMinutesMaximum;
                    mobileTimeSlotsData.days = [
                        ...mobileTimeSlotsData.days,
                        ...mobileTimeSlotsResponse.data.days,
                    ];
                    mobileTimeSlotsData.type = mobileTimeSlotsResponse.data.type;
                    mobileTimeSlotsData.zipCode = mobileTimeSlotsResponse.data.zipCode;
                } else {
                    const inshopTimeSlotsResponse =
                        await baseMixin.methods.dispatchStoreActionWithLogging(
                            storeActionConfig.storeAction,
                            storeActionConfig.payload,
                            "schedule",
                            false
                        );

                    inshopTimeSlotsData.estimatedServiceMinutesMinimum =
                        inshopTimeSlotsResponse.data.estimatedServiceMinutesMinimum;
                    inshopTimeSlotsData.estimatedServiceMinutesMaximum =
                        inshopTimeSlotsResponse.data.estimatedServiceMinutesMaximum;
                    inshopTimeSlotsData.days = [
                        ...inshopTimeSlotsData.days,
                        ...inshopTimeSlotsResponse.data.days,
                    ];
                    inshopTimeSlotsData.type = inshopTimeSlotsResponse.data.type;
                    inshopTimeSlotsData.providerNumber =
                        inshopTimeSlotsResponse.data.providerNumber;
                }
            })
        );
    };

    return makeParallelCalls().then(() => {
        // sort days chronologically
        inshopTimeSlotsData.days.sort(compareDayStrings);
        mobileTimeSlotsData.days.sort(compareDayStrings);

        const todaysDate = getTodayDate().toISOString().split("T")[0];
        inshopTimeSlotsData.days = removePastDates(inshopTimeSlotsData.days, todaysDate);
        mobileTimeSlotsData.days = removePastDates(mobileTimeSlotsData.days, todaysDate);

        return {
            inshopTimeSlotsData: inshopTimeSlotsData,
            mobileTimeSlotsData: mobileTimeSlotsData,
        };
    });
};

const returnFirstDate = (dates) => {
    if (dates.days?.length > 0) {
        return dates.days[0].date;
    } else {
        return null;
    }
};

export default {
    name: "schedule",
    data() {
        return {
            selectedDate: this.getSelectedDateFromStore(),
            selectedTimeSlotInfo: this.getSelectedTimeSlotInfo(),
            mobilePremiumAppointmentFee: null,
            waitListRequested: null,
            displayWaitList: null,
            pricingByDayUpchargeLineItem: null,
            includePricingByDayUpcharge: null,
            isPricingByDayExperiment: null,
            pricingByDayBasePrice: null,
            pricingByDayUpcharge: null,
            showPricingByDay: null,
            selectableDatesInshop: [],
            selectableDatesMobile: [],
            preSelectedDate: null,
            streetAddress: this.getServiceAddressFromStore(),
            apartmentNumberOrBusinessName: this.getServiceAddress2FromStore(),
            carId: this.getCarIdfromStore(),
            city: this.getServiceCityFromStore(),
            state: this.getServiceStateFromStore(),
            zipCode: this.getServiceZipCodeFromStore(),
            isVehicleHeavyTruck: this.getIsVehicleHeavyTruckFromStore(),
            isVehicleProtected: this.getIsVehicleProtectedFromStore(),
            isGlassServiceableInshop: null,
            isRecalibrationServiceableInshop: null,
            isGlassServiceableDropoff: null,
            isRecalibrationServiceableDropoff: null,
            isGlassServiceableMobile: null,
            isRecalibrationServiceableMobile: null,
            appointmentType: this.getAppointmentTypeFromStore(),
            appointmentTypeFromAppointmentTypeQuestion: this.getAppointmentTypeFromStore(),
            selectedProvider: this.getSelectedProviderFromStore(),
            mobileFeePart: null,
            recycleFeePart: null,
            zipContainsMilitaryBase: false,
            zipCodeCtu: null,
            billToAccountNumber: null,
            shopProviderData: null,
            navigatingForward: false,
            shopListButton: shopListButton,
            lastSelectedInshopOrDropoffProvider: null,
        };
    },
    async beforeRouteEnter(to, from, next) {
        const serviceZipCode = store.getters.order.serviceLocation.zipCode;

        const cmsContentPromise = fetchCmsContentForPage(to.name);
        const alertReasonsPromise = locationAlerts.methods.loadInitialData(
            store.getters.order.serviceLocation.zipCodeCtu,
            store.getters.order.serviceLocation.provider?.address?.zipCodeCtu
        );
        const serviceabilityDetailsPromise = getServiceabilityDetails(
            serviceZipCode,
            null,
            "schedule"
        );
        let zipCodeData;
        const zipCodeDataPromise = getZipCodeData(serviceZipCode, to.name);
        let shopProviderData;
        const shopProviderDataPromise = getShopProviderData(serviceZipCode, to.name);
        const zipCodeDataAndShopProviderDataPromise = Promise.all([
            zipCodeDataPromise,
            shopProviderDataPromise,
        ]);
        const mobileFeePartPromise = zipCodeDataAndShopProviderDataPromise.then(
            ([zipCodeDataResult, shopProviderDataResult]) => {
                zipCodeData = zipCodeDataResult;
                shopProviderData = shopProviderDataResult;
                return baseMixin.methods.dispatchStoreActionWithLogging(
                    storeActions.GET_MOBILE_FEE_PART,
                    {
                        serviceZipCode: serviceZipCode,
                        serviceZipCodeCtu: zipCodeData.zipCodeCtu,
                        mobileProviderNumber: shopProviderData.data.mobileProviderNumber,
                    },
                    to.name,
                    false
                );
            }
        );
        const premiumFeePromise = baseMixin.methods.dispatchStoreActionWithLogging(
            storeActions.GET_MOBILE_PREMIUM_FEE,
            null,
            to.name
        );
        // Settle promises and get results
        const promiseResultMap = [
            {
                resultKey: "cmsContent",
                promise: cmsContentPromise,
            },
            {
                resultKey: "alertReasons",
                promise: alertReasonsPromise,
            },
            {
                resultKey: "mobileFeePart",
                promise: mobileFeePartPromise,
            },
            {
                resultKey: "serviceabilityDetails",
                promise: serviceabilityDetailsPromise,
            },
            {
                resultKey: "premiumFee",
                promise: premiumFeePromise,
            },
        ];
        const resultMap = await settleAllPromises(promiseResultMap);
        const itemsToPrice = [];
        if (resultMap.mobileFeePart) {
            itemsToPrice.push(resultMap.mobileFeePart);
        }
        if (resultMap.premiumFee) {
            itemsToPrice.push(resultMap.premiumFee);
        }

        let pricedMobileFeePart = null;
        let pricedPremiumFee = null;

        if (itemsToPrice.length) {
            const pricedItems = await baseMixin.methods.dispatchStoreActionWithLogging(
                storeActions.PRICE_ORDER_ITEMS_AND_SAVE_SERVER_DATA,
                {
                    availableLineItems: itemsToPrice,
                },
                to.name,
                false
            );
            pricedMobileFeePart = pricedItems.find(
                (item) => item.partNumber === resultMap.mobileFeePart.partNumber
            );
            pricedPremiumFee = pricedItems.find(
                (item) => item.partNumber === resultMap.premiumFee.partNumber
            );
        }

        let appointmentType = store.getters.order.serviceLocation.appointmentType;
        //  Check to see if date should be pre-selected
        let scheduleFromStore = await store.getters.order.schedule;
        let preSelectedDate;
        if (scheduleFromStore.date && scheduleFromStore.date.length > 0) {
            preSelectedDate = scheduleFromStore.date;

            if (appointmentType === AppointmentTypeStrings.MOBILE) {
                preSelectedDate += "-mobile";
            }
        }

        // Call the "next" function to complete the transition to this page.
        next((vm) => {
            vm.setCmsContent(resultMap.cmsContent);
            vm.$refs.locationAlerts.initializeComponent(resultMap.alertReasons);
            vm.mobilePremiumAppointmentFee = pricedPremiumFee;
            vm.updateFooterButtonText(vm.selectedTimeSlotInfo);
            vm.pricingByDayUpchargeLineItem = null; // Pricing By Day Upcharge Line Item is not used in this version
            vm.includePricingByDayUpcharge = false; // Pricing By Day Upcharge is not used in this version
            vm.isPricingByDayExperiment = false; // Pricing By Day Experiment is not used in this version
            vm.pricingByDayBasePrice = null; // Pricing By Day Base Price is not used in this version
            vm.pricingByDayUpcharge = null; // Pricing By Day Upcharge is not used in this version
            vm.showPricingByDay = false; // Pricing By Day is not used in this version
            vm.preSelectedDate = preSelectedDate;
            vm.appointmentType = appointmentType;
            vm.setDataOnLoad(
                zipCodeData,
                resultMap.serviceabilityDetails,
                pricedMobileFeePart,
                shopProviderData.data
            );
            vm.initializeDatePicker();
        });
    },
    computed: {
        serviceZipCodeQuestion: {
            get: function () {
                return {
                    state: this.state,
                    zipCode: this.zipCode,
                    zipCodeCtu: this.zipCodeCtu,
                };
            },
            set: function (newValue) {
                this.handleZipCodeChange(newValue);
            },
        },
        isMobileSelected() {
            return this.appointmentType == AppointmentTypeStrings.MOBILE;
        },
        isServiceableMobile() {
            if (this.isRecalibrationServiceableMobile !== null) {
                return (
                    (this.isGlassServiceableMobile && this.isRecalibrationServiceableMobile) ||
                    this.isMobileStaticRecalibrationApplicable
                );
            } else {
                return this.isGlassServiceableMobile;
            }
        },
        showTimeSlotQuestion() {
            if (
                this.selectedDate &&
                this.selectedDate.includes("mobile") &&
                !this.isMobileSelected
            ) {
                this.setSelectedDateToFirstAvailable();
            }
            return this.selectedDate && this.appointmentTypeFromAppointmentTypeQuestion;
        },
        isMobileStaticRecalibrationApplicable() {
            return (
                this.displayMSR &&
                this.mobileFeePart?.partNumber == partNumberStrings.MOBILE_STATIC_RECAL_FEE &&
                (this.isCashItacNoComp || this.mobileFeePart?.isInsurable)
            );
        },
        displayMSR() {
            return (
                experimentMixin.methods
                    .getSettingValue(experimentSettings.DISPLAY_MSR)
                    ?.toLowerCase() === "true"
            );
        },
        isCashItacNoComp() {
            return !this.isInsurance || this.isITAC || this.isNoComp;
        },
        mobileFeeHasPrice() {
            return (
                this.mobileFeePart?.laborAmount > 0 ||
                this.mobileFeePart?.sellingPrice > 0 ||
                this.mobileFeePart?.kitPrice > 0
            );
        },
        mobileFeeApplies() {
            if (this.isMobileStaticRecalibrationApplicable && this.mobileFeeHasPrice) {
                return this.isCashItacNoComp;
            } else {
                return this.mobileFeeHasPrice;
            }
        },
        mobileFeeText() {
            const cmsContentText = this.getCmsContent("MobileFeeDisclaimerWidget", "Text");
            return cmsContentText.replaceAll("{custom:mobileFee}", this.mobileFee);
        },
        mobileFee() {
            if (!this.mobileFeePart) {
                return 0;
            }
            return (
                this.mobileFeePart.laborAmount +
                this.mobileFeePart.sellingPrice +
                this.mobileFeePart.kitPrice
            );
        },
        showMobileFreeAlert() {
            if (this.isServiceableMobile && !this.isInsurance && !this.mobileFeeHasPrice) {
                return true;
            }
            return false;
        },
        isServiceableInshop() {
            if (this.isRecalibrationServiceableInshop !== null) {
                return this.isGlassServiceableInshop && this.isRecalibrationServiceableInshop;
            } else {
                return this.isGlassServiceableInshop;
            }
        },
        isServiceableDropoff() {
            if (this.isRecalibrationServiceableDropoff !== null) {
                return this.isGlassServiceableDropoff && this.isRecalibrationServiceableDropoff;
            } else {
                return this.isGlassServiceableDropoff;
            }
        },
        isShopQuestionDisplayed() {
            return (
                this.appointmentType === AppointmentTypeStrings.IN_SHOP ||
                this.appointmentType === AppointmentTypeStrings.DROP_OFF ||
                AppointmentTypeStrings.IN_SHOP_OR_DROP_OFF
            );
        },
        isAppointmentTypeDisplayed() {
            return (
                this.zipCode &&
                !this.displayNoShopsAlert &&
                this.isServiceableMobile &&
                this.isServiceableInshop
            );
        },
        requiresInshopRecalibration() {
            // Specifically check for isRecalibrationServiceableMobile === false, not null or true.
            return (
                this.isServiceableInshop &&
                this.isGlassServiceableMobile &&
                this.isRecalibrationServiceableMobile === false &&
                !this.isMobileStaticRecalibrationApplicable
            );
        },
        displayRecalibrationWarning() {
            return this.requiresInshopRecalibration;
        },
        displayServiceableInshopOnly() {
            return (
                !this.displayRecalibrationWarning &&
                this.isServiceableInshop &&
                !this.isServiceableMobile
            );
        },
        displayMilitaryZipAlert() {
            return this.zipContainsMilitaryBase && this.isServiceableMobile;
        },
        displayServiceableMobileOnly() {
            return this.isServiceableMobile && !this.isServiceableInshop;
        },
        displayNoShopsAlert() {
            return !this.isServiceableInshop && !this.isServiceableMobile;
        },
        recalibrationInformationModal() {
            return this.$refs.recalibrationInformationModal;
        },
        isInsurance() {
            return store.getters.payment.isInsurance;
        },
        isITAC() {
            return store.getters.order.policy.isItac;
        },
        isNoComp() {
            return store.getters.order.policy.isNoComp;
        },
        isForwardActionDisabled() {
            return !this.selectedTimeSlotInfo?.timeSlot?.routeCode || !this.appointmentType;
        },
        additionalButtonData() {
            return {
                shopAppointmentType: this.appointmentType,
            };
        },
        selectedShopAnswer() {
            const toTitleCase = (str) => {
                if (!str) return "";
                return str.replace(/\w\S*/g, function (txt) {
                    return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
                });
            };

            if (
                this.selectedProvider &&
                this.selectedProvider.address &&
                this.selectedProvider?.providerNumber
            ) {
                const provider = this.shopProviderData?.shopProviders?.find(
                    (p) => p.providerNumber === this.selectedProvider?.providerNumber
                );
                const streetAddress = toTitleCase(this.selectedProvider.address.streetAddress);
                const city = toTitleCase(this.selectedProvider.address.city);
                const state = this.selectedProvider.address.state;
                const zipCode = this.selectedProvider.address.zipCode;
                const distanceInMiles = provider ? Math.round(provider.distanceInMiles * 2) / 2 : 0;

                return {
                    city: `${city}`,
                    distance: `${distanceInMiles} mi`,
                    address1: `${streetAddress}`,
                    address2: `${city}, ${state} ${zipCode}`,
                };
            }
            return [];
        },
        selectedRouteCodeData() {
            if (!this.selectedTimeSlotInfo?.timeSlot?.routeCode) {
                return null;
            }
            return {
                routeCode: this.selectedTimeSlotInfo.timeSlot.routeCode,
                isPremiumAppointment: this.selectedTimeSlotInfo.isPremiumAppointment,
            };
        },
        questionText() {
            return this.getCmsContent("YourSafeliteShopWidget", "QuestionText");
        },
        datePickerHeaderText() {
            return this.getCmsContent("DatePickerSubHeaderWidget", "HeaderText");
        },
        appointmentTypeStrings() {
            return AppointmentTypeStrings;
        },
        ChangeShopLinkText() {
            return this.getCmsContent("ChangeShopLink", "Text");
        },
        ChangeShopLink() {
            // Splits content when brackets are found in text so that text can be looped through and router-link can be injected when needed
            return this.splitCopyOnCMSPlaceHolder(this.ChangeShopLinkText);
        },
        estimatedServiceMinutesMinimum() {
            return this.isMobileSelected
                ? this.selectableDatesMobile.estimatedServiceMinutesMinimum
                : this.selectableDatesInshop.estimatedServiceMinutesMinimum;
        },
        estimatedServiceMinutesMaximum() {
            return this.isMobileSelected
                ? this.selectableDatesMobile.estimatedServiceMinutesMaximum
                : this.selectableDatesInshop.estimatedServiceMinutesMaximum;
        },
        timeSlotsForSelectedDate() {
            if (!this.selectedDate) return null;
            const selectedDate = this.selectedDate;

            if (this.isMobileSelected) {
                const selectedDateString = selectedDate.replace("-mobile", "");
                return this.selectableDatesMobile.days?.find(
                    (selectableDate) => selectableDate.date === selectedDateString
                );
            } else {
                return this.selectableDatesInshop.days?.find(
                    (selectableDate) => selectableDate.date === this.selectedDate
                );
            }
        },
        isSameDay() {
            const todaysDate = getTodayDate().toISOString().split("T")[0];
            return this.selectedDate === todaysDate;
        },
        isOvernightDropoff() {
            return (
                this.selectedTimeSlotInfo?.timeSlot?.routeCode &&
                this.selectedTimeSlotInfo.timeSlot.routeCode.includes(
                    RouteCodeFlags.OVERNIGHT_DROP_OFF
                )
            );
        },
        isMobileFirstModalOpen() {
            return this.isMobileSelected ? this.$refs.mobileFirstModal?.getIsModalOpen() : false;
        },
    },
    methods: {
        splitCopyOnCMSPlaceHolder,
        arePagePrerequisitesValid() {
            const paymentInfo = store.getters.payment.isInsurance !== null;
            const damageInfo =
                store.getters.order.damage.isRepair ||
                (store.getters.order.lineItems?.glassParts != null &&
                    store.getters.order.lineItems.glassParts.length > 0);
            const parentAccountNumberInfo =
                store.getters.payment.parentAccountNumber !==
                applicationConfig.CASH_PARENT_ACCOUNT_NUMBER;
            const policyNumberInfo = store.getters.order.policy.policyNumber;
            const zipCodeInfo = store.getters.order.serviceLocation.zipCode;
            const supportingItemsInfo = store.getters.lineItems.supportingItems;

            // insurance drops the recycle fee on replace orders so it won't be in supportingItems
            const insurancePreReqResult =
                parentAccountNumberInfo &&
                policyNumberInfo &&
                zipCodeInfo &&
                paymentInfo &&
                damageInfo;
            const cashPreReqResult =
                supportingItemsInfo && zipCodeInfo && paymentInfo && damageInfo;

            const outputDebugLog = (preReqResult) => {
                // prettier-ignore
                debugLog("--- schedule.vue pagePrereqs start ---", null, !preReqResult);
                debugLog(
                    "store.getters.payment.isInsurance:",
                    store.getters.payment?.isInsurance,
                    !preReqResult
                );
                debugLog(
                    "store.getters.order.damage.isRepair:",
                    store.getters.order.damage?.isRepair,
                    !preReqResult
                );
                debugLog(
                    "store.getters.order.lineItems.glassParts:",
                    store.getters.order.lineItems?.glassParts,
                    !preReqResult
                );
                debugLog(
                    "store.getters.payment.parentAccountNumber:",
                    store.getters.payment.parentAccountNumber,
                    !preReqResult
                );
                debugLog(
                    "store.getters.order.policy.policyNumber:",
                    store.getters.order.policy.policyNumber,
                    !preReqResult
                );
                debugLog(
                    "store.getters.order.serviceLocation.zipCode:",
                    store.getters.order.serviceLocation.zipCode,
                    !preReqResult
                );
                debugLog(
                    "store.getters.lineItems.supportingItems:",
                    store.getters.lineItems.supportingItems,
                    !preReqResult
                );
                debugLog("--- schedule.vue pagePrereqs end ---", null, !preReqResult);
            };

            if (store.getters.payment.isInsurance) {
                outputDebugLog(insurancePreReqResult);
                return insurancePreReqResult;
            } else {
                outputDebugLog(cashPreReqResult);
                return cashPreReqResult;
            }
        },

        setDataOnLoad(zipCodeData, serviceabilityDetails, mobileFeePart, shopProviderData) {
            if (zipCodeData) {
                this.zipContainsMilitaryBase = zipCodeData.containsMilitaryBase;
                this.zipCodeCtu = zipCodeData.zipCodeCtu;
            }

            if (serviceabilityDetails) {
                this.setServiceabilityDetails(serviceabilityDetails);
            }

            if (mobileFeePart) {
                this.mobileFeePart = mobileFeePart;
            }

            if (shopProviderData) {
                this.shopProviderData = shopProviderData;
                this.updateSelectedProvider(); // ensure that page loads with non-null selectedProvider
            }

            var gaLabel = this.GaLabels.NO;
            if (this.isServiceableMobile) {
                gaLabel = this.GaLabels.YES;
            }
            this.pushEventToGA(
                this.GaCategories.APPOINTMENT,
                this.GaActions.MOBILE_AVAILABLE,
                gaLabel,
                true
            );
        },
        setContainsMilitaryBase(val) {
            if (this.zipContainsMilitaryBase !== val) {
                this.zipContainsMilitaryBase = val;
            }
        },
        setBillToAccountNumber(val) {
            this.billToAccountNumber = val;
        },
        setCtuForMobile(val) {
            this.zipCodeCtu = val;
        },
        setMobileFeePart(mobileFeePart) {
            this.mobileFeePart = mobileFeePart;
        },
        setRecycleFeePart(recycleFeePart) {
            this.recycleFeePart = recycleFeePart;
        },
        getCarIdfromStore() {
            return store.getters.vehicle.carId;
        },
        getServiceAddressFromStore() {
            return store.getters.order.serviceLocation.address;
        },
        getServiceAddress2FromStore() {
            return store.getters.order.serviceLocation.address2;
        },
        getServiceCityFromStore() {
            return store.getters.order.serviceLocation.city;
        },
        getServiceStateFromStore() {
            return store.getters.order.serviceLocation.state;
        },
        getServiceZipCodeFromStore() {
            return store.getters.order.serviceLocation.zipCode;
        },
        getIsVehicleHeavyTruckFromStore() {
            return store.getters.order.vehicle?.isBigTruck ?? false;
        },
        getIsVehicleProtectedFromStore() {
            return store.getters.order.serviceLocation.isVehicleProtected;
        },
        getAppointmentTypeFromStore() {
            return store.getters.order.serviceLocation.appointmentType;
        },
        getSelectedProviderFromStore() {
            return store.getters.order.serviceLocation.provider;
        },
        resetMobileLocation() {
            this.streetAddress = "";
            this.apartmentNumberOrBusinessName = "";
            this.city = "";

            this.isVehicleProtected = null;
        },
        resetWaitlist() {
            this.dispatchStoreAction(this.storeActions.SAVE_WAITLIST_REQUESTED, false, false);
            this.waitListRequested = false;
        },
        onServiceZipChanged() {
            this.resetWaitlist();
            this.appointmentType = null;
            this.selectedProvider = null;
            this.appointmentTypeFromAppointmentTypeQuestion = null;
            this.preSelectedDate = null;
        },
        setServiceabilityDetails(serviceabilityDetails) {
            this.isGlassServiceableInshop = serviceabilityDetails.isGlassServiceableInshop;
            this.isRecalibrationServiceableInshop =
                serviceabilityDetails.isRecalibrationServiceableInshop;
            this.isGlassServiceableDropoff = serviceabilityDetails.isGlassServiceableDropoff;
            this.isRecalibrationServiceableDropoff =
                serviceabilityDetails.isRecalibrationServiceableDropoff;
            this.isGlassServiceableMobile = serviceabilityDetails.isGlassServiceableMobile;
            this.isRecalibrationServiceableMobile =
                serviceabilityDetails.isRecalibrationServiceableMobile;
        },
        async reloadShopData(zipCode) {
            await this.$refs.shopQuestion.reloadShopData(zipCode);
        },
        openRecalibrationInformationModal() {
            this.recalibrationInformationModal.openModal();
        },
        updateAndSaveIsMSRFeeApplicable() {
            const isMSRFeeApplicable =
                this.isMobileStaticRecalibrationApplicable && this.appointmentType == "Mobile";
            this.dispatchStoreAction(
                this.storeActions.SAVE_IS_MSR_FEE_APPLICABLE,
                isMSRFeeApplicable
            );
        },
        updateAndSaveSupportingItems() {
            let supportingItems = store.getters.lineItems.supportingItems;
            let shouldSaveSupportingItems = false;

            supportingItems =
                !supportingItems && this.isMobileStaticRecalibrationApplicable
                    ? []
                    : supportingItems;

            // for insurance orders, fees can get removed causing supportingitems to be null or empty
            if (!supportingItems) {
                return;
            }

            // update recyle fee price
            if (this.recycleFeePart) {
                const recycleFeeIndex = supportingItems.findIndex(
                    (item) => item.partNumber == partNumberStrings.RECYCLE_FEE
                );
                if (recycleFeeIndex >= 0) {
                    supportingItems[recycleFeeIndex].laborAmount = this.recycleFeePart.laborAmount;
                    supportingItems[recycleFeeIndex].sellingPrice =
                        this.recycleFeePart.sellingPrice;
                    supportingItems[recycleFeeIndex].kitPrice = this.recycleFeePart.kitPrice;

                    shouldSaveSupportingItems = true;
                }
            }

            // if we have a mobile fee, then save/update supporting items
            if (this.appointmentType == "Mobile") {
                const mobileFeeIndex = supportingItems.findIndex(
                    (item) => item.partType == MOBILE_FEE_PART_TYPE
                );
                // If it already exists, update the price with latest data
                if (mobileFeeIndex >= 0) {
                    supportingItems[mobileFeeIndex].laborAmount = this.mobileFeePart.laborAmount;
                    supportingItems[mobileFeeIndex].sellingPrice = this.mobileFeePart.sellingPrice;
                    supportingItems[mobileFeeIndex].kitPrice = this.mobileFeePart.kitPrice;
                } else {
                    if (this.mobileFeePart !== null) supportingItems.push(this.mobileFeePart);
                }

                shouldSaveSupportingItems = true;
            } else {
                // if it's not a mobile, then make sure we remove any that may have been added
                const removeMobileFeeIndex = supportingItems?.findIndex(
                    (item) => item.partType == MOBILE_FEE_PART_TYPE
                );

                if (removeMobileFeeIndex >= 0) {
                    supportingItems.splice(removeMobileFeeIndex, 1);
                    shouldSaveSupportingItems = true;
                }
            }

            // Use shouldSaveSupportingItems flag to determine if we need to save supporting items. Prevents unnecessary/multiple saves
            if (shouldSaveSupportingItems) {
                this.dispatchStoreAction(
                    this.storeActions.SAVE_SUPPORTING_ITEMS_SUPPRESSING_STATE_RESETTING,
                    supportingItems,
                    false
                );
            }
        },
        getTimeSlotInfo() {
            // Get the current date
            const currentDate = getTodayDate();

            // Add 10 days to the current date
            currentDate.setDate(currentDate.getDate() + 10);

            // Format the date as yyyy-mm-dd
            const year = currentDate.getFullYear();
            const month = String(currentDate.getMonth() + 1).padStart(2, "0");
            const day = String(currentDate.getDate()).padStart(2, "0");

            const formattedDate = `${year}-${month}-${day}`;

            return {
                date: formattedDate,
                endTime: "12:00",
                jobMaxMinutes: "180",
                jobMinMinutes: "120",
                routeCode: "3357I-03357-M-I*20988*AM",
                startTime: "08:00",
            };
        },
        onShopSelected(shopQuestionPopUpData) {
            this.resetWaitlist();
            this.preSelectedDate = null;
            this.shopProviderData = shopQuestionPopUpData.shopProviderData;
            const oldProvider = this.selectedProvider;
            const selectedProvider = this.shopProviderData.shopProviders.find((shopProvider) => {
                return shopProvider.providerNumber === shopQuestionPopUpData.selectedProviderNumber;
            });

            // No zipCodeData comes back if zip was not changed
            if (shopQuestionPopUpData.zipCodeData) {
                this.updateSelectedProviderAndZipCode(
                    shopQuestionPopUpData.zipCodeData,
                    selectedProvider
                );
            } else {
                const didProviderNumberChange =
                    oldProvider?.providerNumber !== selectedProvider.providerNumber;
                if (didProviderNumberChange) {
                    this.updateSelectedProvider(selectedProvider);
                    this.initializeDatePicker();
                }
            }
        },
        async getMoreScheduleData(startDate, endDate) {
            // called only when "View more dates" is clicked; not on initial page load
            const moreShopTimeSlots = await getScheduleApiResponse({
                startDateString: startDate,
                endDateString: endDate,
                providerNumber: this.selectedProvider?.providerNumber,
                zipCode: this.zipCode,
                includeMobileTimeSlots: this.isServiceableMobile,
                includeInshopTimeSlots: this.isServiceableInshop || this.isServiceableDropoff,
            });

            // ADD API CALL RESULTS TO EXISTING DATE DATA
            this.selectableDatesInshop.days = this.selectableDatesInshop.days.concat(
                moreShopTimeSlots.inshopTimeSlotsData.days
            );
            this.selectableDatesMobile.days = this.selectableDatesMobile.days.concat(
                moreShopTimeSlots.mobileTimeSlotsData.days
            );

            this.showMobileFirstModal();

            return moreShopTimeSlots;
        },

        async initializeDatePicker() {
            this.selectedDate = null;

            const includeMobileTimeSlots = this.isServiceableMobile;
            const includeInshopTimeSlots = this.isServiceableInshop || this.isServiceableDropoff;
            const datePickerInitialData = await this.$refs.datePicker.loadInitialData({
                // setup config options for date-picker
                selectableDatesSetting: "custom",
                initialViewRowsToShow: NUMBER_OF_CALENDAR_ROWS_TO_SHOW_FOR_INITIAL_VIEW,
                getSelectableDatesCallback: getScheduleApiResponse,
                preSelectedDate: this.preSelectedDate,
                providerNumber: this.selectedProvider?.providerNumber,
                zipCode: this.zipCode,
                includeMobileTimeSlots: includeMobileTimeSlots,
                includeInshopTimeSlots: includeInshopTimeSlots,
            });
            datePickerInitialData.pricingByDayBasePrice = this.pricingByDayBasePrice;
            datePickerInitialData.pricingByDayUpcharge = this.pricingByDayUpcharge;
            await this.$refs.datePicker.initializeComponent(datePickerInitialData);
            this.selectableDatesInshop =
                await datePickerInitialData.initialShopTimeSlotsResponse.inshopTimeSlotsData;
            this.selectableDatesMobile =
                await datePickerInitialData.initialShopTimeSlotsResponse.mobileTimeSlotsData;
            this.setDisplayWaitList();

            if (this.preSelectedDate) {
                this.selectedDate = this.preSelectedDate;
            } else {
                // if no date is preselected on load, make sure there are some dates available
                if (
                    (includeInshopTimeSlots && this.selectableDatesInshop.days.length < 1) ||
                    (includeMobileTimeSlots && this.selectableDatesMobile.days.length < 1)
                ) {
                    await this.$nextTick();
                    await this.$refs.datePicker.showAnotherMonth();
                    this.setDisplayWaitList();
                }
            }
        },
        getScheduleApiResponse,
        getServiceZipCtuCodeFromStore() {
            return store.getters.order.serviceLocation.zipCodeCtu;
        },
        getSelectedDateFromStore() {
            let isMobileSelected = this.isMobileSelected;
            if (isMobileSelected === undefined) {
                isMobileSelected = this.appointmentType === AppointmentTypeStrings.MOBILE;
            }
            let storedDate = store.getters.order.schedule.date;
            if (isMobileSelected) storedDate += "-mobile";
            return storedDate;
        },
        getSelectedTimeSlotInfo() {
            const supportingItems = this.getSupportingItems();

            var isPremiumAppointment = false;
            if (supportingItems) {
                isPremiumAppointment =
                    !!supportingItems.filter(
                        (lineItem) => lineItem.partType === PREMIUM_FEE_PART_TYPE
                    ).length > 0;
            }

            const selectedTimeSlotInfo = {
                timeSlot: store.getters.order.schedule,
                isPremiumAppointment: isPremiumAppointment,
            };

            return selectedTimeSlotInfo;
        },
        getSupportingItems() {
            return store.getters.lineItems.supportingItems;
        },
        updateFooterButtonText(timeSlotInfo) {
            let navbarButtonText = "Continue";
            // Archiving the following in case we revert back from Heritage parity
            /*
            if (!timeSlotInfo || !timeSlotInfo.timeSlot.date) {
                navbarButtonText = "Continue";
            } else {
                navbarButtonText = `Select ${this.convertSelectedDateToShortMonthAndDay(
                    timeSlotInfo.timeSlot.date
                )}`;

                if (
                    this.appointmentType === AppointmentTypeStrings.IN_SHOP ||
                    this.appointmentType === AppointmentTypeStrings.DROP_OFF
                ) {
                    if (
                        !timeSlotInfo.timeSlot.routeCode.includes(
                            RouteCodeFlags.ALL_DAY_DROP_OFF
                        ) &&
                        !timeSlotInfo.timeSlot.routeCode.includes(RouteCodeFlags.OVERNIGHT_DROP_OFF)
                    ) {
                        navbarButtonText += ` at ${this.getDisplayTextForMilitaryTime(
                            timeSlotInfo.timeSlot.startTime
                        )}`;
                    }
                } else if (
                    this.appointmentType === AppointmentTypeStrings.MOBILE &&
                    !timeSlotInfo.isPremiumAppointment
                ) {
                    navbarButtonText += ` at ${this.getDisplayTextForMilitaryTime(
                        timeSlotInfo.timeSlot.startTime,
                        true
                    )} - ${this.getDisplayTextForMilitaryTime(
                        timeSlotInfo.timeSlot.endTime,
                        true
                    )}`;
                }
            }
            */
            this.$refs.navbar.updateButtonText(navbarButtonText);
        },
        convertSelectedDateToShortMonthAndDay(selectedDate) {
            // This conversion ensures we don't get get GMT induced date changes
            const dateObject = convertDateStringToDate(selectedDate.replace("-mobile", ""));
            return dateObject.toLocaleDateString("en-us", { month: "short", day: "numeric" });
        },
        getDisplayTextForMilitaryTime(militaryTimeInput, shouldTrimMinutesIfEmpty = false) {
            // Expected input: "HH:MM"
            let hours = parseInt(militaryTimeInput.split(":")[0]);
            const minutes = militaryTimeInput.split(":")[1];
            const meridianNotation = hours > 11 ? "PM" : "AM";

            if (hours > 12) hours -= 12;
            if (shouldTrimMinutesIfEmpty && minutes === "00") {
                return `${hours} ${meridianNotation}`;
            } else {
                return `${hours}:${minutes} ${meridianNotation}`;
            }
        },
        backButtonAction() {
            const payment = store.getters.order.payment;
            if (
                payment?.isInsurance &&
                (payment?.insuranceCoverage?.isVerified ||
                    store.getters.order.referralNumber.length === 6)
            ) {
                navigateToHeritageFunnel({
                    shouldSaveSession: false,
                    pageNameToLog: this.pageName,
                    navType: "back",
                });
            } else {
                this.$router.navigateWithoutSaving(
                    this.navigationScenarios.CLICKED_BACK,
                    this.pageName
                );
            }
        },
        showLoadingModal() {
            this.$refs.loadingModal.showModal();
        },
        async forwardButtonAction() {
            this.navigatingForward = true;
            var ctu = this.zipCodeCtu;
            if (this.appointmentType === AppointmentTypeStrings.MOBILE) {
                if (this.selectedProvider && this.selectedProvider.address) {
                    this.selectedProvider.address.streetAddress = null;
                    this.selectedProvider.address.city = null;
                    this.selectedProvider.address.state = null;
                    this.selectedProvider.address.zipCode = null;
                    this.selectedProvider.address.zipCodeCtu = null;
                }
            } else {
                if (this.zipCodeCtu != this.selectedProvider.address.zipCodeCtu) {
                    ctu = this.selectedProvider.address.zipCodeCtu;
                }
                this.resetMobileLocation();
            }

            await this.dispatchStoreAction(
                this.storeActions.SAVE_SERVICE_LOCATION,
                {
                    address: this.streetAddress,
                    address2: this.apartmentNumberOrBusinessName,
                    city: this.city,
                    state: this.state,
                    zipCode: this.zipCode,
                    zipCodeCtu: ctu,
                    appointmentType: this.appointmentType,
                    isVehicleProtected: this.isVehicleProtected,
                    provider: {
                        providerNumber: this.selectedProvider?.providerNumber,
                        address: {
                            streetAddress: this.selectedProvider?.address?.streetAddress,
                            city: this.selectedProvider?.address?.city,
                            state: this.selectedProvider?.address?.state,
                            zipCode: this.selectedProvider?.address?.zipCode,
                            zipCodeCtu: this.selectedProvider?.address?.zipCodeCtu,
                        },
                    },
                },
                false
            );

            if (this.billToAccountNumber) {
                this.dispatchStoreAction(
                    this.storeActions.SAVE_BILL_TO_ACCOUNT_NUMBER,
                    this.billToAccountNumber,
                    false
                );
            }

            this.updateAndSaveSupportingItems();
            this.updateAndSaveIsMSRFeeApplicable();

            this.updateSupportingItems();

            if (this.displayWaitList) {
                let gaLabel = "";
                let status = this.waitListRequested ? "checked" : "unchecked";
                if (
                    this.waitListRequested === null &&
                    this.$store.state.order.customer.waitListRequested === true
                ) {
                    status = "checked";
                }
                const type = store.getters.isMobileAppointment ? "mobile" : "inshop";
                gaLabel = `${status}_${type}`;

                const currentDate = getTodayDate();
                const dateString = this.isMobileSelected
                    ? this.selectableDatesMobile.days[0].date
                    : this.selectableDatesInshop.days[0].date;
                const [year, month, day] = dateString.split("-").map(Number);
                const appointmentDate = new Date(year, month - 1, day);
                const timeDifference = appointmentDate - currentDate;

                // Convert the time difference from milliseconds to days
                const daysUntilAppointment = Math.ceil(timeDifference / (1000 * 60 * 60 * 24));

                gaLabel +=
                    "_" +
                    daysUntilAppointment.toString() +
                    "_" +
                    store.getters.order.serviceLocation.zipCode +
                    "_" +
                    store.getters.order.serviceLocation.zipCodeCtu;
                this.pushEventToGA("waitlist", "add_to_waitlist_check_box_status", gaLabel, true);
            }

            if (this.selectedTimeSlotInfo.timeSlot.jobMinMinutes == null) {
                this.selectedTimeSlotInfo = this.getSelectedTimeSlotInfo();
                if (this.selectedTimeSlotInfo.timeSlot.jobMinMinutes == null) {
                    this.selectedTimeSlotInfo.timeSlot.jobMinMinutes = this.isMobileSelected
                        ? this.selectableDatesMobile.estimatedServiceMinutesMinimum?.toString()
                        : this.selectableDatesInshop.estimatedServiceMinutesMinimum?.toString();
                    this.selectedTimeSlotInfo.timeSlot.jobMaxMinutes = this.isMobileSelected
                        ? this.selectableDatesMobile.estimatedServiceMinutesMaximum?.toString()
                        : this.selectableDatesInshop.estimatedServiceMinutesMaximum?.toString();
                }
            }

            this.dispatchStoreAction(
                this.storeActions.SAVE_SCHEDULE,
                this.selectedTimeSlotInfo.timeSlot,
                false
            );

            if (this.waitListRequested !== null && this.waitListRequested !== undefined) {
                this.dispatchStoreAction(
                    this.storeActions.SAVE_WAITLIST_REQUESTED,
                    this.waitListRequested,
                    false
                );
            }

            if (this.appointmentType == AppointmentTypeStrings.MOBILE) {
                //navigate to mobile details page
                this.$router.navigateWithSaving(
                    this.navigationScenarios.CLICKED_FORWARD_WITH_MOBILE_SERVICE,
                    this.pageName
                );
            } else {
                this.$router.navigateWithSaving(
                    this.navigationScenarios.CLICKED_FORWARD,
                    this.pageName
                );
            }
            this.showLoadingModal();
        },
        setDisplayWaitList() {
            const dateString = this.isMobileSelected
                ? this.selectableDatesMobile?.days[0]?.date
                : this.selectableDatesInshop?.days[0]?.date;
            if (
                experimentMixin.methods.hasSettingEqualTo(
                    experimentSettings.DISPLAY_WAITLIST,
                    "true"
                ) &&
                dateString
            ) {
                const [year, month, day] = dateString.split("-").map(Number);
                const targetDate = new Date(year, month - 1, day);
                const currentDate = getTodayDate();
                const futureDate = new Date(currentDate);
                const experimentThresholdDays = experimentMixin.methods.hasSetting(
                    experimentSettings.WAITLIST_THRESHOLD_DAYS
                )
                    ? parseInt(
                          experimentMixin.methods.getSettingValue(
                              experimentSettings.WAITLIST_THRESHOLD_DAYS
                          )
                      )
                    : 0;
                futureDate.setDate(currentDate.getDate() + experimentThresholdDays);

                if (targetDate >= futureDate) {
                    this.displayWaitList = true;
                } else {
                    this.displayWaitList = false;
                }
            }
        },
        updateSupportingItems() {
            const supportingItems = this.getSupportingItems();

            // if we have a pricing by day upcharge, then save/update supporting items with it
            const pricingByDayUpchargeFeeIndex = supportingItems?.findIndex(
                (item) => item.partType == PRICING_BY_DAY_PART_TYPE
            );

            if (this.includePricingByDayUpcharge && this.showPricingByDay) {
                if (pricingByDayUpchargeFeeIndex && pricingByDayUpchargeFeeIndex > -1) {
                    supportingItems[pricingByDayUpchargeFeeIndex].laborAmount =
                        this.pricingByDayUpchargeLineItem.laborAmount;
                    supportingItems[pricingByDayUpchargeFeeIndex].sellingPrice =
                        this.pricingByDayUpchargeLineItem.sellingPrice;
                    supportingItems[pricingByDayUpchargeFeeIndex].kitPrice =
                        this.pricingByDayUpchargeLineItem.kitPrice;
                } else {
                    supportingItems.push(this.pricingByDayUpchargeLineItem);
                }
            } else {
                if (pricingByDayUpchargeFeeIndex >= 0) {
                    // remove pricing by day upcharge if it already was in store
                    supportingItems.splice(pricingByDayUpchargeFeeIndex, 1);
                }
            }

            // if we have a premium fee(early bird), then save/update supporting items
            if (
                this.appointmentType === AppointmentTypeStrings.MOBILE &&
                this.selectedTimeSlotInfo?.isPremiumAppointment
            ) {
                const premiumFeeIndex = supportingItems.findIndex(
                    (item) => item.partType == PREMIUM_FEE_PART_TYPE
                );

                if (premiumFeeIndex > -1) {
                    supportingItems[premiumFeeIndex].laborAmount =
                        this.mobilePremiumAppointmentFee.laborAmount;
                    supportingItems[premiumFeeIndex].sellingPrice =
                        this.mobilePremiumAppointmentFee.sellingPrice;
                    supportingItems[premiumFeeIndex].kitPrice =
                        this.mobilePremiumAppointmentFee.kitPrice;
                } else {
                    supportingItems.push(this.mobilePremiumAppointmentFee);
                }
            } else {
                if (!supportingItems) {
                    return;
                }

                // if it's not a mobile and/or premium early bird, then make sure we remove any that may have been added
                const removePremiumFeeIndex = supportingItems.findIndex(
                    (item) => item.partType == PREMIUM_FEE_PART_TYPE
                );

                if (removePremiumFeeIndex >= 0) {
                    supportingItems.splice(removePremiumFeeIndex, 1);
                }
            }

            this.dispatchStoreAction(
                this.storeActions.SAVE_SUPPORTING_ITEMS_SUPPRESSING_STATE_RESETTING,
                supportingItems,
                false
            );
        },
        handleWaitListRequested(value) {
            this.waitListRequested = value;
        },
        handleDateClicked(date) {
            // do something to mark this as upcharge day or not...
            if (date.isPricingByDayUpchargeDay) {
                this.includePricingByDayUpcharge = true;
            } else {
                this.includePricingByDayUpcharge = false;
            }
        },
        updateTimeSlot(timeSlotObj) {
            if (!timeSlotObj?.routeCode) {
                this.appointmentType = AppointmentTypeStrings.IN_SHOP_OR_DROP_OFF;
                this.selectedTimeSlotInfo = {
                    timeSlot: {
                        date: null,
                        routeCode: null,
                        startTime: null,
                        endTime: null,
                        jobMaxMinutes: null,
                        jobMinMinutes: null,
                    },
                    isPremiumAppointment: null,
                };
                return;
            }
            const timeSlot = this.timeSlotsForSelectedDate?.timeSlots?.find(
                (slot) => slot.id == timeSlotObj.routeCode
            );

            this.selectedTimeSlotInfo = {
                timeSlot: {
                    date: this.timeSlotsForSelectedDate.date,
                    routeCode: timeSlotObj.routeCode,
                    startTime: timeSlot.startTime,
                    endTime: timeSlot.endTime,
                    jobMaxMinutes: this.estimatedServiceMinutesMaximum.toString(),
                    jobMinMinutes: this.estimatedServiceMinutesMinimum.toString(),
                },
                isPremiumAppointment: timeSlotObj.isPremiumAppointment ? true : false,
            };

            if (
                this.appointmentType !== AppointmentTypeStrings.MOBILE &&
                this.appointmentType !== null
            ) {
                // update apptType based on routeCode to determine if it should be dropoff or inshop
                debugLog(`Updating appointment type based on route code.`);
                debugLog(`Route code =`, timeSlotObj.routeCode);
                debugLog(`Parsed type = `, this.getInShopOrDropOffApptType(timeSlotObj.routeCode));
                this.appointmentType = this.getInShopOrDropOffApptType(timeSlotObj.routeCode);
            }
        },
        getInShopOrDropOffApptType(routeCode) {
            return isDropOffRouteCode(routeCode)
                ? AppointmentTypeStrings.DROP_OFF
                : AppointmentTypeStrings.IN_SHOP;
        },
        getFirstAvailableDate() {
            let dateToSelect;
            if (this.isMobileSelected) {
                dateToSelect = returnFirstDate(this.selectableDatesMobile);
            } else {
                dateToSelect = returnFirstDate(this.selectableDatesInshop);
            }
            if (!dateToSelect) return null;
            return this.isMobileSelected ? dateToSelect + "-mobile" : dateToSelect;
        },
        resetSelectedProvider() {
            this.selectedProvider = new Provider();
            this.updateSelectedProvider();
        },
        updateSelectedProvider(newShopProvider) {
            if (newShopProvider) {
                this.selectedProvider = newShopProvider;
            } else if (this.appointmentType === this.appointmentTypeStrings.MOBILE) {
                this.selectedProvider = {
                    providerNumber: this.shopProviderData.mobileProviderNumber.toString(),
                    address: {
                        streetAddress: null,
                        city: null,
                        state: null,
                        zipCode: null,
                        zipCodeCtu: null,
                    },
                };
            } else if (
                (!this.selectedProvider?.address?.streetAddress || this.isVehicleHeavyTruck) &&
                this.shopProviderData?.shopProviders?.length
            ) {
                this.selectedProvider = this.shopProviderData.shopProviders[0];
            }
        },
        handleZipCodeChange(newZipCode) {
            this.resetMobileLocation();

            getShopProviderData(newZipCode.zipCode, this.pageName).then((result) => {
                this.shopProviderData = result.data;
                this.resetSelectedProvider();
                this.state = newZipCode.state;
                this.zipCode = newZipCode.zipCode;
                this.zipCodeCtu = newZipCode.zipCodeCtu;
                this.selectedDate = null;
                this.initializeDatePicker();
            });
        },
        updateSelectedProviderAndZipCode(newZipCode, newProvider) {
            this.resetMobileLocation();
            this.state = newZipCode.state;
            this.zipCode = newZipCode.zipCode;
            this.zipCodeCtu = newZipCode.zipCodeCtu;
            this.zipContainsMilitaryBase = newZipCode.containsMilitaryBase;
            this.selectedDate = null;
            this.selectedProvider = newProvider;
            this.initializeDatePicker();
        },
        handleAppointmentTypeChange(newAppointmentType) {
            this.updateFooterButtonText();
            if (newAppointmentType === AppointmentTypeStrings.MOBILE) {
                // Remember last shop selected if previous selection was inshop/dropoff
                if (
                    (this.appointmentType == AppointmentTypeStrings.IN_SHOP ||
                        AppointmentTypeStrings.DROP_OFF ||
                        AppointmentTypeStrings.IN_SHOP_OR_DROP_OFF) &&
                    this.selectedProvider
                ) {
                    this.selectedTimeSlotInfo = {
                        timeSlot: {
                            date: null,
                            routeCode: null,
                            startTime: null,
                            endTime: null,
                            jobMaxMinutes: null,
                            jobMinMinutes: null,
                        },
                        isPremiumAppointment: null,
                    };
                    this.lastSelectedInshopOrDropoffProvider = this.selectedProvider;
                }
                this.appointmentType = AppointmentTypeStrings.MOBILE;
                this.updateSelectedProvider();
                this.showMobileFirstModal();
            } else if (newAppointmentType) {
                if (this.appointmentType != AppointmentTypeStrings.MOBILE) {
                    // Clear last shop selected if appointment type was changed in any manner other than from Mobile
                    this.lastSelectedInshopOrDropoffProvider = null;
                }
                if (this.selectedTimeSlotInfo?.timeSlot?.routeCode) {
                    // update appointmentType based on routeCode to determine if it should be dropoff or inshop
                    this.appointmentType = this.getInShopOrDropOffApptType(
                        this.selectedTimeSlotInfo.timeSlot.routeCode
                    );
                } else {
                    this.appointmentType = AppointmentTypeStrings.IN_SHOP_OR_DROP_OFF;
                }
                // make sure a selectedProvider exists
                this.updateSelectedProvider(this.lastSelectedInshopOrDropoffProvider);
            } else {
                this.appointmentType = null;
            }
            this.setSelectedDateToFirstAvailable();
            this.setDisplayWaitList();
        },
        setSelectedDateToFirstAvailable() {
            this.selectedDate = this.getFirstAvailableDate();
        },
        async showMobileFirstModal() {
            if (this.appointmentType == AppointmentTypeStrings.MOBILE) {
                const isShowMobileFirstAppt = experimentMixin.methods.hasSettingEqualTo(
                    experimentSettings.SHOW_MOBILE_FIRST_APPT,
                    "true"
                );
                const pmMobileDays = experimentMixin.methods.getSettingValue(
                    experimentSettings.SHOW_PM_MOBILE_DAYS
                );
                const noPMMobileDays = experimentMixin.methods.getSettingValue(
                    experimentSettings.SHOW_NO_PM_MOBILE_DAYS
                );
                const noMobileAvailableDays = experimentMixin.methods.getSettingValue(
                    experimentSettings.SHOW_NO_MOBILE_AVAILABLE_DAYS
                );

                let preSelectedMobileAppointment = null;
                const todaysDate = getTodayDate();
                let firstMobileAMAppt = await this.getFirstAvailableMobileApptByTOD("AM");
                let firstMobilePMAppt = await this.getFirstAvailableMobileApptByTOD("PM");
                if (!firstMobileAMAppt && !firstMobilePMAppt) {
                    return;
                }
                let firstMobileAMDate = firstMobileAMAppt ? firstMobileAMAppt.date : null;
                let firstMobilePMDate = firstMobilePMAppt ? firstMobilePMAppt.date : null;
                let numberOfDaysToFirstMobileAMDate =
                    (new Date(firstMobileAMDate) - todaysDate) / (1000 * 60 * 60 * 24);
                let numberOfDaysToFirstMobilePMDate =
                    (new Date(firstMobilePMDate) - todaysDate) / (1000 * 60 * 60 * 24);

                const shouldExposeMobileFirstAppointment = () => {
                    return (
                        (firstMobileAMDate &&
                            numberOfDaysToFirstMobileAMDate <= noMobileAvailableDays) ||
                        (firstMobilePMDate &&
                            numberOfDaysToFirstMobilePMDate <= noMobileAvailableDays)
                    );
                };

                if (shouldExposeMobileFirstAppointment()) {
                    const mobileFirstExperiment = store.getters.applicationUser.experiments.find(
                        (e) => e.universeName === experimentUniverses.MOBILE_FIRST_APPOINTMENT
                    );
                    const hasExposedMobileFirst = mobileFirstExperiment?.isExposed;

                    if (!hasExposedMobileFirst && mobileFirstExperiment) {
                        baseMixin.methods.dispatchStoreActionWithLogging(
                            storeActions.LOG_EXPERIMENT_EXPOSURE_AND_UPDATE_STORE,
                            {
                                userId: getUserIdValue(),
                                deviceId: getDeviceIdValue(),
                                sessionKey: getSessionKeyValue(),
                                pageName: "schedule",
                                experiment: mobileFirstExperiment,
                            },
                            "schedule",
                            false
                        );
                    }

                    if (isShowMobileFirstAppt) {
                        if (firstMobilePMDate && numberOfDaysToFirstMobilePMDate <= pmMobileDays) {
                            preSelectedMobileAppointment = firstMobilePMAppt;
                        } else if (
                            firstMobilePMDate &&
                            numberOfDaysToFirstMobilePMDate >= noPMMobileDays
                        ) {
                            preSelectedMobileAppointment = firstMobileAMAppt
                                ? firstMobileAMAppt
                                : null;
                            !preSelectedMobileAppointment &&
                                (preSelectedMobileAppointment = firstMobilePMAppt);
                        }

                        this.$refs.mobileFirstModal.setSelectedAppointment(
                            preSelectedMobileAppointment
                        );
                        this.$refs.mobileFirstModal.openModal();
                    }
                }
            }
        },
        async getFirstAvailableMobileApptByTOD(timeOfDay) {
            if (!this.selectableDatesMobile.days) {
                await this.initializeDatePicker();
            }
            if (!this.selectableDatesMobile?.days?.length) {
                return null;
            } else {
                for (const dateObj of this.selectableDatesMobile.days) {
                    let matchingTimeSlot = {
                        estimatedServiceMinutes: {
                            minimum: this.estimatedServiceMinutesMinimum,
                            maximum: this.estimatedServiceMinutesMaximum,
                        },
                        timeSlot: null,
                        date: null,
                    };
                    const isMatchingApptDay = dateObj.timeSlots.some(
                        (slot) =>
                            slot.id.includes(timeOfDay) &&
                            (matchingTimeSlot.timeSlot = slot) &&
                            (matchingTimeSlot.date = dateObj.date)
                    );
                    if (isMatchingApptDay && matchingTimeSlot) {
                        return matchingTimeSlot;
                    }
                }
                return null;
            }
        },
        updateTimeSlotandNavigateForward(timeSlotObj) {
            this.updateTimeSlot(timeSlotObj);
            this.forwardButtonAction();
        },
    },
    watch: {
        appointmentTypeFromAppointmentTypeQuestion: {
            handler(newValue, oldValue) {
                this.handleAppointmentTypeChange(newValue);
            },
        },
        selectedDate(newValue, oldValue) {
            // Clear time slot selection if date selected changes
            const selectedDate = this.getSelectedDateFromStore();
            if (oldValue && this.appointmentType === AppointmentTypeStrings.MOBILE) {
                oldValue = `${oldValue}-mobile`;
            }
            const hasValueChanged = newValue !== oldValue;
            const isDateDifferent = (newValue || oldValue) !== selectedDate;

            if (hasValueChanged && isDateDifferent) {
                this.selectedTimeSlotInfo = {
                    timeSlot: {
                        date: null,
                        routeCode: null,
                        startTime: null,
                        endTime: null,
                        jobMaxMinutes: null,
                        jobMinMinutes: null,
                    },
                    isPremiumAppointment: null,
                };
            }
        },
        selectedTimeSlotInfo(newValue) {
            this.updateFooterButtonText(newValue);
        },
    },
    components: {
        funnelHeader,
        navbar,
        funnelSubHeader,
        Form,
        loadingModal,
        datePicker,
        locationAlerts,
        textBlock,
        timeSlotQuestion,
        mobileFirstModal,

        alert,
        serviceZipModalQuestion,
        appointmentTypeQuestion,
        contentGroupModal,
        durationTextBlock,
        shopLocation,
        mobileFeeWaiverAlert,
    },
};
</script>

<style lang="scss" scoped>
.container {
    .question-text {
        margin-bottom: 1.5rem;

        & > span {
            display: flex;
            justify-content: flex-start;
            margin-bottom: 0.25rem;
        }
    }
    &.hidden-background {
        display: none;
    }
}
.alert.alert-warning {
    .alert-heading {
        color: $black;
        font-family: UrbanistSemibold;
        font-size: 1rem;
    }
}

.shop-question-button .list-button-content {
    background: $blue-100;
    box-shadow: 0 0 0 1px $primary;
}

.container .row .col-12 .alert-success .alert-heading {
    color: $black;
    font-weight: 600;
}

:deep(.funnel-sub-header:not(#schedule-your-service)) {
    h5.dark-header {
        font-weight: 600;
        font-size: 1rem;
    }
}
:deep(.funnel-sub-header#schedule-your-service) {
    h5.dark-header {
        margin-bottom: 0;
    }
}

.col-12 a {
    font-family: UrbanistSemibold;
    font-weight: 600;
    line-height: 26px;
    text-underline-offset: 4px;
}

:deep(.text-block.duration-text-block b) {
    font-family: UrbanistSemibold;
}
:deep(.alert-warning.widget-name-AlertRecalNoMobileWidget .alert-heading),
:deep(.alert-success.widget-name-AlertMobileFeeFreeWidget .alert-heading) {
    color: $black;
    font-weight: 600;
    font-size: 1rem;

    * {
        color: $black;
        font-weight: 600;
        font-size: 1rem;
    }
}
</style>
