<template>
    <Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }">
        <div class="page-container-grouped-styles">
            <loadingModal ref="loadingModal" />
            <funnelHeader cmsWidgetName="FunnelHeaderWidget" />
            <funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" class="mt-5" />
            <div class="text-center mt-1 mb-3" v-if="ChangeShopLink.length">
                <span v-for="copy in ChangeShopLink" :key="copy">
                    <span v-if="doesCopyContainRouterLink(copy)" class="text-body">
                        <router-link
                            :to="{
                                query: { fmgPage: `${getRouterLinkRouteFromCopy(copy)}` },
                                name: 'root',
                            }"
                            >{{ getRouterLinkDisplayTextFromCopy(copy) }}</router-link
                        >
                    </span>
                    <span v-else class="m-0 text-body" v-html="copy"></span>
                </span>
            </div>
            <location-alerts cmsWidgetPrefix="LocationAlert-" ref="locationAlerts" />
            <date-picker
                selectableDatesSetting="custom"
                ref="datePicker"
                v-model="selectedDate"
                :customSelectableDatesCallback="getAvailableDatesMethod"
                @date-clicked="openInshopTimeSlotsModal" />
            <time-slot-modal-question
                ref="timeSlotModalQuestion"
                cmsWidgetName="TimeSlotModalQuestion"
                mobilePremiumCmsWidgetName="MobilePremiumTimeSlotModal"
                mobileCmsWidgetName="MobileTimeSlotModal"
                dropoffCmsWidgetName="DropOffTimeSlotModal"
                sameDayDropOffCmsWidgetName="SameDayDropOffTimeSlotModal"
                v-model="selectedTimeSlotData"
                @time-slot-modal-closed="timeSlotModalClosed"
                :appointmentType="appointmentType"
                :premiumAppointmentFee="mobilePremiumAppointmentFee"
                :dateAndTimeSlotData="timeSlotsForSelectedDate"
                :estimatedServiceMinutesMinimum="selectableDatesData.estimatedServiceMinutesMinimum"
                :estimatedServiceMinutesMaximum="selectableDatesData.estimatedServiceMinutesMaximum"
                validationRules="time-slot-selection-required" />
            <funnel-footer
                cmsWidgetName="FunnelFooterWidget"
                ref="funnelFooter"
                :isForwardActionDisabled="!meta.valid"
                @back-clicked="backButtonAction"
                @ForwardClicked="forwardButtonAction" />
        </div>
    </Form>
</template>

<script>
// Components
import funnelHeader from "@/fmg-components/funnel-header/funnel-header";
import funnelFooter from "@/fmg-components/funnel-footer/funnel-footer";
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 datePicker from "@/digital-components/date-picker/date-picker";
import locationAlerts from "@/layouts/schedule/location-alerts/location-alerts";
import timeSlotModalQuestion from "./time-slot-modal-question/time-slot-modal-question";

// Supporting files
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import baseMixin from "@/mixins/base-mixin.js";
import { storeActions } from "@/constants/store-actions";
import { settleAllPromises } from "@/helpers/layout-helper";
import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
import {
    doesCopyContainRouterLink,
    splitCopyOnCMSPlaceHolder,
    getRouterLinkRouteFromCopy,
    getRouterLinkDisplayTextFromCopy,
} from "@/helpers/cms-content-helper";
import { AppointmentTypeStrings } from "./constants/schedule-constants";
import { errorMessages } from "@/constants/error-messages";
import { required } from "@/helpers/validation-rules";
import store from "@/store";

defineRule("date-required", required(errorMessages.DATE_REQUIRED));
defineRule("time-slot-selection-required", required(errorMessages.DATE_REQUIRED));

const getAvailableDates = async (startDate, endDate, appointmentType, providerNumber) => {
    // USING DATES PASSED, MAKE AN API CALL

    let newTimeSlotsResponse;
    if (appointmentType === AppointmentTypeStrings.MOBILE) {
        newTimeSlotsResponse = await baseMixin.methods.dispatchStoreAction(
            storeActions.GET_MOBILE_TIME_SLOTS,
            {
                startDate: startDate,
                endDate: endDate,
            },
            false
        );
    } else {
        newTimeSlotsResponse = await baseMixin.methods.dispatchStoreAction(
            storeActions.GET_SHOP_TIME_SLOTS,
            {
                startDate: startDate,
                endDate: endDate,
                shopAppointmentType: appointmentType,
                providerNumber: providerNumber,
            },
            false
        );
    }

    return newTimeSlotsResponse.data;
};

export default {
    name: "schedule",
    data() {
        return {
            selectedDate: this.getSelectedDate(),
            selectedTimeSlotData: {
                id: this.getSelectedRouteCode(),
                isPremiumAppointment: null,
            },
            selectableDatesData: [],
            mobilePremiumAppointmentFee: null,
        };
    },
    async beforeRouteEnter(to, from, next) {
        // Call APIs
        const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage);
        const datePickerInitialDataPromise = datePicker.methods.loadInitialData({
            // setup config options for date-picker
            selectableDatesSetting: "custom",
            initialViewRowsToShow: 5,
            customSelectableDatesCallback: getAvailableDates,
        });

        const premiumFeePromise = baseMixin.methods.dispatchStoreAction(
            storeActions.GET_MOBILE_PREMIUM_FEE
        );

        const premiumFeeWithPricePromise = premiumFeePromise.then((result) => {
            if (result.data) {
                return baseMixin.methods.dispatchStoreAction(
                    storeActions.PRICE_ORDER_ITEMS_AND_SAVE_SERVER_DATA,
                    {
                        availableLineItems: [result.data],
                    },
                    false
                );
            } else {
                return result.data;
            }
        });

        const alertReasonsPromise = locationAlerts.methods.loadInitialData(
            store.getters.order.serviceLocation.zipCodeCtu
        );
        // Settle promises and get results
        const promiseResultMap = [
            {
                resultKey: "cmsContent",
                promise: cmsContentPromise,
            },
            {
                resultKey: "alertReasons",
                promise: alertReasonsPromise,
            },
            {
                resultKey: "datePickerInitialData",
                promise: datePickerInitialDataPromise,
            },
            {
                resultKey: "premiumFeeWithPrice",
                promise: premiumFeeWithPricePromise,
            },
        ];

        const resultMap = await settleAllPromises(promiseResultMap);

        // Call the "next" function to complete the transition to this page.
        next((vm) => {
            vm.setCmsContent(resultMap.cmsContent);
            vm.$refs.datePicker.initializeComponent(resultMap.datePickerInitialData);
            vm.$refs.locationAlerts.initializeComponent(resultMap.alertReasons);
            vm.selectableDatesData = resultMap.datePickerInitialData.initialShopTimeSlotsResponse;
            vm.mobilePremiumAppointmentFee = resultMap.premiumFeeWithPrice
                ? resultMap.premiumFeeWithPrice[0]
                : null;
            vm.updateFooterButtonText(vm.selectedTimeSlotData);
        });
    },
    computed: {
        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);
        },
        appointmentType() {
            return this.$store.getters.order.serviceLocation.appointmentType;
        },
        timeSlotsForSelectedDate() {
            if (!this.selectedDate) {
                return null;
            }
            return this.selectableDatesData.days?.find(
                (selectableDate) => selectableDate.date === this.selectedDate
            );
        },
        appointmentDateAndTime() {
            if (!this.selectedTimeSlotData.id) {
                return null;
            }
            const timeSlotSelectedObject = this.getTimeSlotObjectFromTimeSlotId(
                this.selectedTimeSlotData.id
            );
            if (timeSlotSelectedObject) {
                return {
                    date: this.selectedDate,
                    startTime: timeSlotSelectedObject.startTime,
                    endTime: timeSlotSelectedObject.endTime,
                    routeCode: this.selectedTimeSlotData.id,
                    jobMaxMinutes:
                        this.selectableDatesData.estimatedServiceMinutesMaximum.toString(),
                };
            } else {
                return null;
            }
        },
    },
    methods: {
        doesCopyContainRouterLink,
        splitCopyOnCMSPlaceHolder,
        getRouterLinkRouteFromCopy,
        getRouterLinkDisplayTextFromCopy,
        arePagePrerequisitesValid() {
            const serviceLocation = store.getters.order.serviceLocation;
            const serviceLocationPreReqs =
                serviceLocation.zipCode &&
                serviceLocation.zipCodeCtu &&
                serviceLocation.appointmentType &&
                (serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE ||
                    serviceLocation.provider.providerNumber);
            const paymentInfo = store.getters.payment.isInsurance !== null;
            const supportingItems = store.getters.lineItems.supportingItems !== null;
            const damageInfo =
                store.getters.order.damage.isRepair ||
                (store.getters.order.lineItems?.glassParts != null &&
                    store.getters.order.lineItems.glassParts.length > 0);
            return serviceLocationPreReqs && paymentInfo && supportingItems && damageInfo;
        },
        async getAvailableDatesMethod(startDate, endDate) {
            const newShopTimeSlots = await getAvailableDates(
                startDate,
                endDate,
                this.appointmentType,
                this.$store.getters.order.serviceLocation.provider.providerNumber
            );
            // ADD API CALL RESULTS TO EXISTING DATE DATA
            this.selectableDatesData.days = this.selectableDatesData.days.concat(
                newShopTimeSlots.days
            );
            return newShopTimeSlots;
        },
        getServiceZipCtuCodeFromStore() {
            return store.getters.order.serviceLocation.zipCodeCtu;
        },
        openInshopTimeSlotsModal() {
            this.$refs["timeSlotModalQuestion"].openModal();
        },
        getTimeSlotObjectFromTimeSlotId(timeSlotId) {
            const timeSlots = this.selectableDatesData.days.find(
                (selectableDate) => selectableDate.date === this.selectedDate
            ).timeSlots;
            return timeSlots.find((timeSlot) => timeSlot.id === timeSlotId);
        },
        getSelectedDate() {
            return store.getters.order.schedule.date;
        },
        getSelectedRouteCode() {
            return store.getters.order.schedule.routeCode;
        },
        timeSlotModalClosed() {
            // Clear the selectedDate if no timeSlot has been selected
            if (!this.selectedTimeSlotData.id) {
                this.selectedDate = null;
            }
        },
        updateFooterButtonText(timeSlotData) {
            let funnelFooterButtonText;
            if (!timeSlotData.id) {
                funnelFooterButtonText = "Continue";
            } else {
                funnelFooterButtonText =
                    "Select " + this.convertSelectedDateToShortMonthAndDay(this.selectedDate);

                if (this.appointmentType === AppointmentTypeStrings.IN_SHOP) {
                    funnelFooterButtonText +=
                        " at " +
                        this.getDisplayTextForMilitaryTime(this.appointmentDateAndTime.startTime);
                } else if (
                    this.appointmentType === AppointmentTypeStrings.MOBILE &&
                    !timeSlotData.isPremiumAppointment
                ) {
                    funnelFooterButtonText +=
                        " at " +
                        this.getDisplayTextForMilitaryTime(
                            this.appointmentDateAndTime.startTime,
                            true
                        ) +
                        " - " +
                        this.getDisplayTextForMilitaryTime(
                            this.appointmentDateAndTime.endTime,
                            true
                        );
                }
            }

            this.$refs.funnelFooter.updateButtonText(funnelFooterButtonText);
        },
        convertSelectedDateToShortMonthAndDay(selectedDate) {
            // This conversion ensures we don't get get GMT induced date changes
            const dateObject = new Date(`${selectedDate}T00:00:00`);
            // Ex: April 25
            return dateObject.toLocaleDateString("en-us", { month: "short", day: "numeric" });
        },
        // Expected input: "HH:MM"
        getDisplayTextForMilitaryTime(militaryTimeInput, shouldTrimMinutesIfEmpty = false) {
            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() {
            this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route);
        },
        async forwardButtonAction() {
            this.dispatchStoreAction(
                this.storeActions.SAVE_SCHEDULE,
                this.appointmentDateAndTime,
                false
            );
            navigateToHeritageFunnel({ loadingModal: this.$refs.loadingModal });
        },
    },
    watch: {
        selectedDate(newValue, oldValue) {
            // Clear time slot selection if date selected changes
            if (newValue !== oldValue) {
                this.selectedTimeSlotData = {
                    id: null,
                    isPremiumAppointment: null,
                };
            }
        },
        selectedTimeSlotData(newValue) {
            this.updateFooterButtonText(this.selectedTimeSlotData);
        },
    },
    components: {
        funnelHeader,
        funnelFooter,
        funnelSubHeader,
        Form,
        loadingModal,
        datePicker,
        locationAlerts,
        timeSlotModalQuestion,
    },
};
</script>
