<template>
    <Form
        ref="theForm"
        @submit="onSubmit"
        @invalidSubmit="onInvalidSubmit">
        <div class="fade-on-route-transition">
            <div class="justify-content-center">
                <siteHeader
                    class="header"
                    cmsWidgetName="SiteHeaderWidget" />
            </div>
            <div class="iss-heritage-container-width">
                <div class="schedule-page-container iss-heritage-content-container-width">
                    <siteSubHeader
                        cmsWidgetName="ScheduleSubHeaderWidget"
                        secondaryTextClasses="text-center small sub-text"
                        class="mt-4" />
                    <div class="main-content-container">
                        <locationAlerts
                            ref="locationAlerts"
                            cmsWidgetPrefix="LocationAlert-" />
                        <datePicker
                            ref="datePicker"
                            v-model="selectedTimeSlotInfo"
                            customComponentId="dateQuestion"
                            selectableDatesSetting="custom"
                            class="text-link-small"
                            :showTimeSlotError="showDatePickerError"
                            :customSelectableDatesCallback="
                                getAvailableDatesMethod
                            "
                            @dateSelected="dateSelectedFromPicker"
                            @timeSlotSelected="timeSlotSelectedFromPicker" />
                        <siteFooter
                            ref="navbar"
                            class="mt-5"
                            cmsWidgetName="SiteFooterWidget"
                            :isForwardButtonNavigationDisabled="!isFormValid"
                            @backClicked="navigateBack"
                            @forwardClicked="forwardButtonAction" />
                    </div>
                </div>
            </div>
        </div>
    </Form>
</template>
<script>
// Components
import siteHeader from '@/iss-components/site-header/site-header.vue';
import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header.vue';
import locationAlerts from '@/layouts/schedule-page/location-alerts/location-alerts.vue';
import datePicker from '@/digital-components/date-picker/date-picker.vue';
import siteFooter from '@/iss-components/site-footer/site-footer.vue';

// Supporting files
import {
    AppointmentTypeStrings,
    GET_MOBILE_TIME_SLOTS,
    GET_SHOP_TIME_SLOTS,
    PREMIUM_FEE_PART_TYPE
} from '@/constants/schedule-constants.js';
import {
    fetchCmsContentForPage,
    splitCopyOnCMSPlaceHolder
} from '@/helpers/cms-content-helper';
import {
    calcDaysBetweenDates,
    sumDateString
} from '@/helpers/date-helper';
import settleAllPromises from '@/helpers/layout-helper';
import { Form } from 'vee-validate';
import BaseFormMixin from '@/mixins/base-form-mixin.js';
import { useMainStore } from '@/store';

// Define constants
const TIME_SLOTS_CALL_DAYS_LIMIT = 15;

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

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

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

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

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

    const timeSlotsResponsesData = {
        days: []
    };

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

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

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

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

export default {
    name: 'schedule-page',
    components: {
        siteHeader,
        siteSubHeader,
        locationAlerts,
        datePicker,
        siteFooter,
        // eslint-disable-next-line vue/no-reserved-component-names
        Form
    },
    mixins: [BaseFormMixin],
    async beforeRouteEnter(to, from, next) {
        // Call APIs
        let preSelectedDate = await useMainStore().order.schedule.date;
        if (!preSelectedDate || preSelectedDate.startTime === null) {
            preSelectedDate = null;
        }

        const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);

        const datePickerInitialDataPromise =
            await datePicker.methods.loadInitialData({
                selectableDatesSetting: 'custom',
                initialViewRowsToShow: 5,
                customSelectableDatesCallback: getAvailableDates,
                preSelectedDate
            });

        const premiumFeePromise = useMainStore().getMobilePremiumFee();

        const premiumFeeWithPricePromise = premiumFeePromise.then((result) => {
            if (result.data) {
                return useMainStore().getCombinedQuote(result.data);
            }
            return result.data;
        });

        const alertReasonsPromise = locationAlerts.methods.loadInitialData(
            useMainStore().order.serviceLocation.zipCodeCtu,
            useMainStore().order.serviceLocation.provider?.address?.zipCodeCtu
        );

        // Settle promises and get results
        const promiseResultMap = [
            {
                resultKey: 'cmsContent',
                promise: cmsContentPromise
            },
            {
                resultKey: 'alertReasons',
                promise: alertReasonsPromise
            },
            {
                resultKey: 'datePickerInitialData',
                promise: datePickerInitialDataPromise
            },
            {
                resultKey: 'premiumFeeWithPrice',
                promise: premiumFeeWithPricePromise
            }
        ];

        // use resultMap to populate layout content.
        const resultMap = await settleAllPromises(promiseResultMap);
        next((vm) => {
            vm.setCmsContent(resultMap.cmsContent);
            vm.$refs.datePicker.initializeComponent(resultMap.datePickerInitialData);
            vm.$refs.locationAlerts.initializeComponent(resultMap.alertReasons);
            vm.setData(
                resultMap.datePickerInitialData.initialShopTimeSlotsResponse,
                resultMap.premiumFeeWithPrice
            );
        });
    },
    setup() {
        const mainStore = useMainStore();
        return { mainStore };
    },
    data() {
        return {
            selectedDate: this.getSelectedDate(),
            selectedTimeSlotInfo: this.getSelectedTimeSlotInfo(),
            selectableDatesData: [],
            showDatePickerError: false,
            mobilePremiumAppointmentFee: null
        };
    },
    computed: {
        ChangeShopLinkText() {
            return this.getCmsContent('ChangeShopLink', 'Text');
        },
        ChangeShopLink() {
            return this.splitCopyOnCMSPlaceHolder(this.ChangeShopLinkText);
        },
        appointmentType() {
            return useMainStore().order.serviceLocation.appointmentType;
        },
        isFormValid() {
            const hasTimeSlotSelected = this.selectedTimeSlotInfo?.timeSlot?.routeCode != null;
            return hasTimeSlotSelected;
        },
        supportingItems() {
            return useMainStore().lineItems.supportingItems;
        }
    },
    methods: {
        splitCopyOnCMSPlaceHolder,
        arePagePrerequisitesValid() {
            const { serviceLocation } = useMainStore().order;
            const serviceLocationPreReqs =
                serviceLocation.zipCode
                && serviceLocation.zipCodeCtu
                && serviceLocation.appointmentType
                && (serviceLocation.appointmentType
                    === AppointmentTypeStrings.MOBILE
                    || serviceLocation.appointmentType
                        === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP
                    || serviceLocation.provider.providerNumber);
            const supportingItems = this.supportingItems !== null;
            const damageInfo =
                useMainStore().order.damage.isRepair
                || (useMainStore().order.lineItems?.glassParts != null
                    && useMainStore().order.lineItems.glassParts.length > 0);

            return serviceLocationPreReqs && supportingItems && damageInfo;
        },
        setData(initialShopTimeSlotsResponse, premiumFeeWithPriceResponse) {
            this.selectableDatesData = initialShopTimeSlotsResponse;
            this.mobilePremiumAppointmentFee = premiumFeeWithPriceResponse
                ? premiumFeeWithPriceResponse[0]
                : null;
        },
        async getAvailableDatesMethod(startDate, endDate) {
            const newShopTimeSlots = await getAvailableDates(
                startDate,
                endDate,
                this.appointmentType,
                this.mainStore.order.serviceLocation.provider.providerNumber
            );
            // ADD API CALL RESULTS TO EXISTING DATE DATA
            this.selectableDatesData.days =
                this.selectableDatesData.days.concat(newShopTimeSlots.days);
            return newShopTimeSlots;
        },
        getAvailableDates,
        getServiceZipCtuCodeFromStore() {
            return this.mainStore.order.serviceLocation.zipCodeCtu;
        },
        getSelectedDate() {
            return this.mainStore.order.schedule.date;
        },
        getSelectedTimeSlotInfo() {
            const isPremiumAppointment =
                !!(
                    this.supportingItems?.filter((lineItem) =>
                        lineItem.partType === PREMIUM_FEE_PART_TYPE) ?? []
                ).length > 0;

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

            return selectedTimeSlotInfo;
        },
        dateSelectedFromPicker(date) {
            this.selectedDate = date;
            this.showDatePickerError = false;
        },
        timeSlotSelectedFromPicker(timeSlot) {
            this.selectedTimeSlotInfo = timeSlot;
            this.showDatePickerError = false;
        },
        forwardButtonAction() {
            if (!this.isFormValid) {
                this.showDatePickerError = true;
                return;
            }

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

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

.iss-heritage-container-width {
    .schedule-page-container {
        position: relative;
        min-height: 1px;
        padding-left: .9375rem;
        padding-right: .9375rem;
    }
}

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

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

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