<template>
    <Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm">
        <interceptOverlay v-if="isLoadingDates || isLoadingMoreShops" />
        <funnelHeader cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" />
        <div class="container page-container-grouped-styles">
            <div class="row">
                <div class="col-12 col-md-10 col-lg-8 col-xl-7">
                    <funnelSubHeader
                        cmsWidgetName="FunnelSubHeaderWidget"
                        :overrideHeaderSubText="estimatedTimeText"
                        alignLeft />
                    <schedulingZipSearch
                        ref="schedulingZipSearch"
                        v-model="zipSearchCode"
                        :disabled="isLoadingDates"
                        :pageNameToLog="pageName"
                        @zip-searched="onZipSearched" />
                    <datePicker
                        :key="datePickerKey"
                        class="mt-5"
                        v-model="selectedDate"
                        :startDate="datePickerStartDate"
                        :endDate="datePickerEndDate"
                        :availableDates="availableDates"
                        :isLoadingDates="isLoadingDates"
                        @requestMoreDates="handleRequestMoreDates" />
                    <Transition name="card-slide" mode="out-in">
                        <div :key="selectedDate">
                            <mobileSchedulingCard
                                v-if="showMobileSchedulingCard"
                                class="mt-4"
                                v-model="selectedScheduling"
                                :providerNumber="mobileProviderAndTimeSlot.providerNumber"
                                :timeSlots="mobileTimeSlotsForSelectedDate"
                                :premiumTimeSlotPrice="premiumTimeSlotPrice"
                                :zipCode="serviceZipCode"
                                :showFreeFlag="showMobileFreeFlag"
                                :radioGroupName="schedulingRadioGroupName"
                                :isLoading="isLoadingDates"
                                @zip-code-clicked="onMobileZipCodeClicked" />
                            <inshopSchedulingCard
                                v-for="entry in inshopProvidersAndTimeSlots"
                                v-show="showInshopSchedulingCards"
                                :key="entry.provider.providerNumber"
                                class="mt-4"
                                v-model="selectedScheduling"
                                :provider="entry.provider"
                                :timeSlots="
                                    getInshopTimeSlotsForSelectedDate(entry.provider.providerNumber)
                                "
                                :radioGroupName="schedulingRadioGroupName"
                                :isLoading="isLoadingDates || Boolean(entry.isLoadingTimeSlots)"
                                @address-clicked="onInshopAddressClicked(entry.provider)" />
                        </div>
                    </Transition>
                    <div class="d-flex justify-content-center mt-4">
                        <textLink
                            v-if="hasMoreShopsAvailable"
                            id="viewMoreShopsLinkId"
                            linkType="text"
                            :text="viewMoreShopsText"
                            href="javascript:void(0)"
                            @click-event="onViewMoreShopsClick">
                            <template #after-text>
                                <span class="spacing-gap"></span>
                                <img
                                    class="chevron-icon"
                                    src="@/assets/img/icons/chevron-no-background.svg"
                                    alt=""
                                    aria-hidden="true" />
                            </template>
                        </textLink>
                    </div>

                    <waitlistQuestion
                        class="mt-5"
                        v-model="isWaitlistRequested"
                        :availableDates="availableDates" />
                    <navbar
                        cmsWidgetName="FunnelFooterWidget"
                        ref="navbar"
                        @back-clicked="backButtonAction"
                        @ForwardClicked="forwardButtonAction" />
                </div>
            </div>
        </div>
    </Form>
</template>

<script>
import funnelHeader from "@/fmg-components/funnel-header/funnel-header";
import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header";
import navbar from "@/fmg-components/nav-bar/nav-bar";
import { Form } from "vee-validate";
import datePicker from "@/layouts/scheduling/date-picker/date-picker";
import mobileSchedulingCard from "@/layouts/scheduling/mobile-scheduling-card/mobile-scheduling-card";
import inshopSchedulingCard from "@/layouts/scheduling/inshop-scheduling-card/inshop-scheduling-card";
import interceptOverlay from "@/ux-components/intercept-overlay/intercept-overlay";
import waitlistQuestion from "@/layouts/scheduling/waitlist-question/waitlist-question";
import schedulingZipSearch from "@/layouts/scheduling/scheduling-zip-search/scheduling-zip-search";
import textLink from "@/ux-components/text-link/text-link";
import store from "@/store";
import { storeActions } from "@/constants/store-actions";
import { AppointmentTypeStrings, PREMIUM_FEE_PART_TYPE } from "@/constants/schedule-constants";
import { isDropOffRouteCode } from "@/layouts/schedule/helpers/schedule-helper";
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { settleAllPromises } from "@/helpers/layout-helper";
import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
import { getDisplayTextForDurationLength } from "@/helpers/duration-length-helper";
import {
    flushPagePrereqsLogs,
    hasServiceZipInfo,
    hasGlassPartsOrRepairInfo,
    hasInsuranceInfo,
} from "@/helpers/page-prerequisites-helper.js";

/**
 * Returns a YYYY-MM-DD date string offset by the given number of days from a base date.
 * @param {number} offsetDays - Number of days to offset (positive or negative).
 * @param {Date} base - The starting date (defaults to today).
 */
function toDateString(offsetDays, base = new Date()) {
    // Adding T00:00:00 ensures the date is treated as a local date in the browser's timezone.
    const d = typeof base === "string" ? new Date(base + "T00:00:00") : new Date(base);
    d.setDate(d.getDate() + offsetDays);
    return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
}

const SCHEDULE_FETCH_DAYS = 15;
const SCHEDULING_RADIO_GROUP_NAME = "schedulingTimeSlot";
const INITIAL_INSHOP_PROVIDER_COUNT = 3;
const MAX_INSHOP_PROVIDERS = 9;
const VIEW_MORE_SHOPS_BATCH_SIZE = 3;
const INSHOP_MAPS_PLACE_NAME = "safelite,Safelite Autoglass";

/**
 * Appends days from newSlots into entry.timeSlots, initializing it if absent.
 * @param {{ timeSlots: { days: any[] } | null }} entry
 * @param {{ days: any[] } | null | undefined} newSlots
 */
function appendDays(entry, newSlots) {
    if (!newSlots) return;
    if (!entry.timeSlots) {
        entry.timeSlots = newSlots;
    } else {
        entry.timeSlots.days = [...(entry.timeSlots.days ?? []), ...(newSlots.days ?? [])];
    }
}

/**
 * Assigns time slots from a v2 multi-provider response onto in-shop provider entries.
 * @param {Array<{ provider: { providerNumber: string }, timeSlots: any }>} entries
 * @param {{ providerTimeSlots?: Array<{ providerNumber: string, days: any[], provisionalTriggers?: string[] }>, estimatedServiceMinutesMinimum?: number, estimatedServiceMinutesMaximum?: number } | null | undefined} multiProviderResponse
 */
function assignInshopTimeSlotsFromV2Response(entries, multiProviderResponse) {
    const providerTimeSlots = multiProviderResponse?.providerTimeSlots ?? [];
    entries.forEach((entry) => {
        const matchedSlots =
            providerTimeSlots.find((pts) => pts.providerNumber === entry.provider.providerNumber) ??
            null;
        if (matchedSlots) {
            matchedSlots.estimatedServiceMinutesMinimum =
                matchedSlots.estimatedServiceMinutesMinimum ??
                multiProviderResponse?.estimatedServiceMinutesMinimum;
            matchedSlots.estimatedServiceMinutesMaximum =
                matchedSlots.estimatedServiceMinutesMaximum ??
                multiProviderResponse?.estimatedServiceMinutesMaximum;
        }
        entry.timeSlots = matchedSlots;
    });
}

/**
 * Appends days from a v2 multi-provider response onto existing in-shop provider entries.
 * @param {Array<{ provider: { providerNumber: string }, timeSlots: any }>} entries
 * @param {{ providerTimeSlots?: Array<{ providerNumber: string, days: any[] }> } | null | undefined} multiProviderResponse
 */
function appendInshopTimeSlotsFromV2Response(entries, multiProviderResponse) {
    const providerTimeSlots = multiProviderResponse?.providerTimeSlots ?? [];
    entries.forEach((entry) => {
        const newSlots = providerTimeSlots.find(
            (pts) => pts.providerNumber === entry.provider.providerNumber
        );
        appendDays(entry, newSlots);
    });
}

/**
 * Returns a promise for inshop time slots for multiple providers.
 * @param {{ startDate: string, endDate: string, providerNumbers: string[], pageNameToLog: string }} params
 */
function fetchInshopTimeSlots({ startDate, endDate, providerNumbers, pageNameToLog }) {
    return store.dispatch("getShopTimeSlotsV2", {
        payload: {
            startDate,
            endDate,
            shopAppointmentType: "InshopOrDropoff",
            providerNumbers,
        },
        pageNameToLog,
    });
}

/**
 * Returns a promise for mobile time slots.
 * @param {{ startDate: string, endDate: string, zipCode: string, pageNameToLog: string }} params
 */
function fetchMobileTimeSlots({ startDate, endDate, zipCode, pageNameToLog }) {
    return store.dispatch("getMobileTimeSlotsV2", {
        payload: {
            startDate,
            endDate,
            zipCode,
        },
        pageNameToLog,
    });
}

/**
 * Fetches inshop time slots (when providers are given) and mobile time slots (when requested)
 * for a date range, settling both requests together. Either request is omitted entirely when
 * it has no applicable providers/zip, rather than firing an empty/unnecessary call.
 * @param {{
 *   startDate: string,
 *   endDate: string,
 *   providerNumbers: string[],
 *   zipCode?: string,
 *   includeMobile?: boolean,
 *   pageNameToLog: string,
 * }} params
 * @returns {Promise<{ inshopTimeSlots?: any, mobileTimeSlots?: any }>}
 */
function fetchTimeSlotsBatch({
    startDate,
    endDate,
    providerNumbers,
    zipCode,
    includeMobile,
    pageNameToLog,
}) {
    return settleAllPromises([
        ...(providerNumbers.length
            ? [
                  {
                      resultKey: "inshopTimeSlots",
                      promise: fetchInshopTimeSlots({
                          startDate,
                          endDate,
                          providerNumbers,
                          pageNameToLog,
                      }),
                  },
              ]
            : []),
        ...(includeMobile
            ? [
                  {
                      resultKey: "mobileTimeSlots",
                      promise: fetchMobileTimeSlots({
                          startDate,
                          endDate,
                          zipCode,
                          pageNameToLog,
                      }),
                  },
              ]
            : []),
    ]);
}

export default {
    name: "scheduling",
    async beforeRouteEnter(to, from, next) {
        const serviceZipCode = store.getters.order.serviceLocation.zipCode;

        const promiseResultMap = [
            {
                resultKey: "cmsContent",
                promise: fetchCmsContentForPage(to.name),
            },
            {
                resultKey: "mobilePremiumFee",
                promise: store.dispatch("getMobilePremiumFee", {
                    pageNameToLog: to.name,
                }),
            },
            {
                resultKey: "providers",
                promise: store.dispatch("getProviders", {
                    payload: { serviceZipCode },
                    pageNameToLog: to.name,
                }),
            },
        ];
        const resultMap = await settleAllPromises(promiseResultMap);
        next(async (vm) => {
            vm.setCmsContent(resultMap.cmsContent);
            await vm.loadSchedulingData(serviceZipCode, {
                providersResult: resultMap.providers,
                pageNameToLog: to.name,
            });
            vm.mobilePremiumAppointmentFee = resultMap.mobilePremiumFee ?? null;
            vm.isLoadingDates = false;
        });
    },
    watch: {
        selectedDate() {
            this.selectedScheduling = null;
        },
    },
    computed: {
        schedulingRadioGroupName() {
            return SCHEDULING_RADIO_GROUP_NAME;
        },
        serviceLocationText() {
            return this.getCmsContent("ServiceLocationText", "Text");
        },
        viewMoreShopsText() {
            return this.getCmsContent("ViewMoreShopsWidget", "Text");
        },
        estimatedTimeText() {
            if (!this.estimatedServiceMinutesMinimum || !this.estimatedServiceMinutesMaximum) {
                return " ";
            }
            const durationText = getDisplayTextForDurationLength(
                this.estimatedServiceMinutesMinimum,
                this.estimatedServiceMinutesMaximum
            );
            return this.getCmsContent("FunnelSubHeaderWidget", "HeaderSubText").replace(
                "{custom:DURATION}",
                durationText
            );
        },
        serviceZipCode() {
            return store.getters.order.serviceLocation.zipCode;
        },
        showMobileSchedulingCard() {
            return Boolean(
                this.mobileProviderAndTimeSlot && (this.selectedDate || this.isLoadingDates)
            );
        },
        showInshopSchedulingCards() {
            return this.selectedDate || this.isLoadingDates;
        },
        mobileTimeSlotsForSelectedDate() {
            if (!this.selectedDate) {
                return [];
            }
            const day = this.mobileProviderAndTimeSlot?.timeSlots?.days?.find(
                (d) => d.date === this.selectedDate
            );
            return day?.timeSlots ?? [];
        },
        premiumTimeSlotPrice() {
            if (this.mobilePremiumAppointmentFee?.partType !== PREMIUM_FEE_PART_TYPE) {
                return null;
            }
            return this.getTotalLineItemPrice(this.mobilePremiumAppointmentFee);
        },
        showMobileFreeFlag() {
            return true;
        },
        availableDates() {
            if (!this.datesLoaded) return null;
            const inshopDates = this.inshopProvidersAndTimeSlots.flatMap(({ timeSlots }) =>
                (timeSlots?.days ?? []).map((d) => d.date)
            );
            const mobileDates = (this.mobileProviderAndTimeSlot?.timeSlots?.days ?? []).map(
                (d) => d.date
            );
            return [...new Set([...inshopDates, ...mobileDates])].sort();
        },
        hasMoreShopsAvailable() {
            const maxVisible = Math.min(MAX_INSHOP_PROVIDERS, this.allShopProviders.length);
            return this.inshopProvidersAndTimeSlots.length < maxVisible;
        },
    },
    data() {
        return {
            selectedDate: null,
            isLoadingDates: true,
            datesLoaded: false,
            datePickerStartDate: toDateString(0),
            datePickerEndDate: toDateString(SCHEDULE_FETCH_DAYS - 1),
            estimatedServiceMinutesMinimum: null,
            estimatedServiceMinutesMaximum: null,
            inshopProvidersAndTimeSlots: [],
            allShopProviders: [],
            mobileProviderAndTimeSlot: null,
            mobilePremiumAppointmentFee: null,
            selectedScheduling: null,
            isWaitlistRequested: false,
            isLoadingMoreShops: false,
            zipSearchCode: store.getters.order.serviceLocation.zipCode ?? "",
            datePickerKey: 0,
            billToAccountNumber: store.getters.order.payment?.billToAccountNumber ?? null,
        };
    },
    methods: {
        async loadSchedulingData(
            serviceZipCode,
            { providersResult = null, pageNameToLog = this.pageName } = {}
        ) {
            let providersData = providersResult;
            if (!providersData) {
                providersData = await store.dispatch("getProviders", {
                    payload: { serviceZipCode },
                    pageNameToLog,
                });
            }
            if (providersData?.shopProviders === undefined) {
                providersData = providersData?.data ?? {};
            }

            const allShopProviders = providersData.shopProviders ?? [];
            const providers = allShopProviders.slice(0, INITIAL_INSHOP_PROVIDER_COUNT);
            const mobileProviderNumber = providersData?.mobileProviderNumber ?? null;

            this.allShopProviders = allShopProviders;
            this.inshopProvidersAndTimeSlots = providers.map((provider) => ({
                provider,
                timeSlots: null,
            }));
            this.mobileProviderAndTimeSlot = mobileProviderNumber
                ? { providerNumber: mobileProviderNumber, timeSlots: null }
                : null;

            const startDate = toDateString(0);
            const endDate = toDateString(SCHEDULE_FETCH_DAYS - 1);
            const providerNumbers = providers.map((provider) => provider.providerNumber);
            const timeSlotsResultMap = await fetchTimeSlotsBatch({
                startDate,
                endDate,
                providerNumbers,
                zipCode: serviceZipCode,
                includeMobile: Boolean(mobileProviderNumber),
                pageNameToLog,
            });

            if (timeSlotsResultMap.inshopTimeSlots) {
                this.estimatedServiceMinutesMinimum =
                    timeSlotsResultMap.inshopTimeSlots.estimatedServiceMinutesMinimum;
                this.estimatedServiceMinutesMaximum =
                    timeSlotsResultMap.inshopTimeSlots.estimatedServiceMinutesMaximum;
            } else if (timeSlotsResultMap.mobileTimeSlots) {
                this.estimatedServiceMinutesMinimum =
                    timeSlotsResultMap.mobileTimeSlots.estimatedServiceMinutesMinimum;
                this.estimatedServiceMinutesMaximum =
                    timeSlotsResultMap.mobileTimeSlots.estimatedServiceMinutesMaximum;
            } else {
                this.estimatedServiceMinutesMinimum = null;
                this.estimatedServiceMinutesMaximum = null;
            }

            assignInshopTimeSlotsFromV2Response(
                this.inshopProvidersAndTimeSlots,
                timeSlotsResultMap.inshopTimeSlots
            );
            if (this.mobileProviderAndTimeSlot) {
                this.mobileProviderAndTimeSlot.timeSlots =
                    timeSlotsResultMap.mobileTimeSlots ?? null;
            }
            this.datesLoaded = true;
        },
        getInshopTimeSlotsForSelectedDate(providerNumber) {
            if (!this.selectedDate) {
                return [];
            }
            const providerEntry = this.inshopProvidersAndTimeSlots.find(
                ({ provider }) => provider.providerNumber === providerNumber
            );
            const day = providerEntry?.timeSlots?.days?.find((d) => d.date === this.selectedDate);
            return day?.timeSlots ?? [];
        },
        buildInshopMapsQuery(address) {
            const streetAddress = address?.streetAddress?.trim();
            if (!streetAddress) {
                return null;
            }
            const street = [streetAddress, address.streetAddress2?.trim()]
                .filter(Boolean)
                .join(" ");
            return `${INSHOP_MAPS_PLACE_NAME}, ${street}, ${address.city}, ${address.state} ${address.zipCode}`;
        },
        buildInshopMapsUrl(address) {
            const query = this.buildInshopMapsQuery(address);
            if (!query) {
                return null;
            }
            if (this.isAppleBrowser()) {
                return `https://maps.apple.com/?q=${encodeURIComponent(query)}`;
            }
            return `https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(query)}`;
        },
        onInshopAddressClicked(provider) {
            const url = this.buildInshopMapsUrl(provider?.address);
            if (!url) {
                return;
            }
            window.open(url, "_blank", "noopener,noreferrer");
        },
        onMobileZipCodeClicked() {
            this.$refs.schedulingZipSearch?.focusZipInput();
        },
        async onZipSearched({ zipCode, billToAccountNumber }) {
            this.billToAccountNumber = billToAccountNumber;
            this.isLoadingDates = true;
            try {
                this.selectedDate = null;
                this.selectedScheduling = null;
                this.isWaitlistRequested = false;
                this.isLoadingMoreShops = false;
                this.datesLoaded = false;
                this.datePickerKey += 1;
                this.datePickerStartDate = toDateString(0);
                this.datePickerEndDate = toDateString(SCHEDULE_FETCH_DAYS - 1);
                await this.loadSchedulingData(zipCode);
            } finally {
                this.isLoadingDates = false;
            }
        },
        async onViewMoreShopsClick() {
            if (this.isLoadingDates || this.isLoadingMoreShops) return;

            const maxVisible = Math.min(MAX_INSHOP_PROVIDERS, this.allShopProviders.length);
            const remainingCapacity = maxVisible - this.inshopProvidersAndTimeSlots.length;
            if (remainingCapacity <= 0) return;

            const displayedProviderNumbers = new Set(
                this.inshopProvidersAndTimeSlots.map(({ provider }) => provider.providerNumber)
            );
            const newProviders = this.allShopProviders
                .filter((provider) => !displayedProviderNumbers.has(provider.providerNumber))
                .slice(0, Math.min(VIEW_MORE_SHOPS_BATCH_SIZE, remainingCapacity));

            if (!newProviders.length) return;

            const newEntries = newProviders.map((provider) => ({
                provider,
                timeSlots: null,
                isLoadingTimeSlots: true,
            }));
            this.inshopProvidersAndTimeSlots = [...this.inshopProvidersAndTimeSlots, ...newEntries];
            this.isLoadingMoreShops = true;

            try {
                const resultMap = await fetchTimeSlotsBatch({
                    startDate: this.datePickerStartDate,
                    endDate: this.datePickerEndDate,
                    providerNumbers: newProviders.map((provider) => provider.providerNumber),
                    pageNameToLog: this.pageName,
                });
                assignInshopTimeSlotsFromV2Response(newEntries, resultMap.inshopTimeSlots);
            } finally {
                newEntries.forEach((entry) => {
                    entry.isLoadingTimeSlots = false;
                });
                this.isLoadingMoreShops = false;
            }
        },
        arePagePrerequisitesValid() {
            const order = store.getters.order;
            const logQueue = [];

            const serviceZip = hasServiceZipInfo(order, logQueue);
            const glassPartsOrRepair = hasGlassPartsOrRepairInfo(order, logQueue);
            const insuranceInfo = hasInsuranceInfo(order, logQueue);

            const preReqResult = serviceZip && insuranceInfo && glassPartsOrRepair;
            flushPagePrereqsLogs("scheduling.vue", preReqResult, logQueue);
            return preReqResult;
        },
        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
                );
            }
        },
        async handleRequestMoreDates() {
            this.isLoadingDates = true;

            const newStartDate = toDateString(1, this.datePickerEndDate);
            const newEndDate = toDateString(SCHEDULE_FETCH_DAYS, this.datePickerEndDate);
            const providerNumbers = this.inshopProvidersAndTimeSlots.map(
                ({ provider }) => provider.providerNumber
            );

            const resultMap = await fetchTimeSlotsBatch({
                startDate: newStartDate,
                endDate: newEndDate,
                providerNumbers,
                zipCode: this.serviceZipCode,
                includeMobile: Boolean(this.mobileProviderAndTimeSlot),
                pageNameToLog: this.pageName,
            });

            appendInshopTimeSlotsFromV2Response(
                this.inshopProvidersAndTimeSlots,
                resultMap.inshopTimeSlots
            );

            if (this.mobileProviderAndTimeSlot) {
                appendDays(this.mobileProviderAndTimeSlot, resultMap.mobileTimeSlots);
            }

            this.datePickerEndDate = newEndDate;
            this.isLoadingDates = false;
        },
        getInShopOrDropOffApptType(selectedScheduling = this.selectedScheduling) {
            if (selectedScheduling?.appointmentType === AppointmentTypeStrings.MOBILE) {
                return AppointmentTypeStrings.MOBILE;
            }
            return isDropOffRouteCode(selectedScheduling?.routeCodeId)
                ? AppointmentTypeStrings.DROP_OFF
                : AppointmentTypeStrings.IN_SHOP;
        },
        getSelectedProvider(appointmentType, selectedScheduling = this.selectedScheduling) {
            if (appointmentType === AppointmentTypeStrings.MOBILE) {
                return {
                    providerNumber: selectedScheduling?.providerNumber,
                    address: {
                        streetAddress: null,
                        city: null,
                        state: null,
                        zipCode: null,
                        zipCodeCtu: null,
                    },
                };
            }
            return (
                this.inshopProvidersAndTimeSlots.find(
                    ({ provider }) => provider.providerNumber === selectedScheduling?.providerNumber
                )?.provider ?? null
            );
        },
        getSelectedTimeSlot(
            appointmentType,
            selectedScheduling = this.selectedScheduling,
            selectedDate = this.selectedDate
        ) {
            const routeCodeId = selectedScheduling?.routeCodeId;
            if (!routeCodeId || !selectedDate) {
                return null;
            }

            let timeSlots;
            if (appointmentType === AppointmentTypeStrings.MOBILE) {
                const day = this.mobileProviderAndTimeSlot?.timeSlots?.days?.find(
                    (d) => d.date === selectedDate
                );
                timeSlots = day?.timeSlots ?? [];
            } else {
                const providerEntry = this.inshopProvidersAndTimeSlots.find(
                    ({ provider }) => provider.providerNumber === selectedScheduling.providerNumber
                );
                const day = providerEntry?.timeSlots?.days?.find((d) => d.date === selectedDate);
                timeSlots = day?.timeSlots ?? [];
            }

            return timeSlots.find((timeSlot) => timeSlot.id === routeCodeId) ?? null;
        },
        getEstimatedServiceMinutes(appointmentType, selectedScheduling = this.selectedScheduling) {
            if (appointmentType === AppointmentTypeStrings.MOBILE) {
                return {
                    minimum:
                        this.mobileProviderAndTimeSlot?.timeSlots?.estimatedServiceMinutesMinimum,
                    maximum:
                        this.mobileProviderAndTimeSlot?.timeSlots?.estimatedServiceMinutesMaximum,
                };
            }

            const providerEntry = this.inshopProvidersAndTimeSlots.find(
                ({ provider }) => provider.providerNumber === selectedScheduling?.providerNumber
            );
            return {
                minimum: providerEntry?.timeSlots?.estimatedServiceMinutesMinimum,
                maximum: providerEntry?.timeSlots?.estimatedServiceMinutesMaximum,
            };
        },
        updateSupportingItems(selectedScheduling = this.selectedScheduling) {
            const supportingItems = store.getters.lineItems?.supportingItems;
            if (!supportingItems) {
                return;
            }

            const isPremiumMobile =
                selectedScheduling?.appointmentType === AppointmentTypeStrings.MOBILE &&
                selectedScheduling?.isPremiumAppointment;

            if (isPremiumMobile && this.mobilePremiumAppointmentFee) {
                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 {
                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
            );
        },
        async forwardButtonAction() {
            const selectedScheduling = this.selectedScheduling;
            const selectedDate = this.selectedDate;

            const appointmentType = this.getInShopOrDropOffApptType(selectedScheduling);
            const selectedProvider = this.getSelectedProvider(appointmentType, selectedScheduling);
            const serviceLocation = store.getters.order.serviceLocation;
            const isMobile = appointmentType === AppointmentTypeStrings.MOBILE;

            let zipCodeCtu = serviceLocation.zipCodeCtu;
            if (
                !isMobile &&
                selectedProvider?.address?.zipCodeCtu &&
                zipCodeCtu !== selectedProvider.address.zipCodeCtu
            ) {
                zipCodeCtu = selectedProvider.address.zipCodeCtu;
            }

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

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

            this.updateSupportingItems(selectedScheduling);

            const selectedTimeSlot = this.getSelectedTimeSlot(
                appointmentType,
                selectedScheduling,
                selectedDate
            );
            const estimatedServiceMinutes = this.getEstimatedServiceMinutes(
                appointmentType,
                selectedScheduling
            );

            this.dispatchStoreAction(
                this.storeActions.SAVE_SCHEDULE,
                {
                    date: selectedDate,
                    routeCode: selectedScheduling?.routeCodeId ?? null,
                    startTime: selectedTimeSlot?.startTime ?? null,
                    endTime: selectedTimeSlot?.endTime ?? null,
                    jobMinMinutes: estimatedServiceMinutes.minimum?.toString() ?? null,
                    jobMaxMinutes: estimatedServiceMinutes.maximum?.toString() ?? null,
                },
                false
            );

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

            if (isMobile) {
                this.$router.navigateWithSaving(
                    this.navigationScenarios.CLICKED_FORWARD_WITH_MOBILE_SERVICE,
                    this.pageName
                );
            } else {
                this.$router.navigateWithSaving(
                    this.navigationScenarios.CLICKED_FORWARD,
                    this.pageName
                );
            }
        },
    },
    components: {
        funnelHeader,
        funnelSubHeader,
        navbar,
        Form,
        datePicker,
        mobileSchedulingCard,
        inshopSchedulingCard,
        interceptOverlay,
        waitlistQuestion,
        schedulingZipSearch,
        textLink,
    },
};
</script>
<style lang="scss" scoped>
.dark-header {
    color: $black;
}
h5 {
    line-height: 32px;
    font-size: 1.25rem;
}

.card-slide-enter-active {
    transition:
        opacity 0.3s ease-out,
        transform 0.3s ease-out;
}
.card-slide-leave-active {
    transition: opacity 0.32s ease-in;
}
.card-slide-enter-from {
    opacity: 0;
    transform: translateX(24px);
}
.card-slide-leave-to {
    opacity: 0;
}
.chevron-icon {
    width: 16px;
    height: 16px;
    flex-shrink: 0;
    transform: rotate(180deg);
    transition: transform 150ms linear;
    vertical-align: baseline;
}
.spacing-gap {
    margin-right: 6.5px;
}

:deep(.text-link) {
    font-weight: 600;
}
</style>
