<template>
    <modal
        :ref="modalName"
        :headerText="dateSelectedReadableDate"
        :footerButtonText="footerCloseButtonText"
        :onModalClosedCallback="onModalClosed"
        class="time-slots-modal"
        @isModalOpened="setModalStatus"
        @footer-button-event="setSelectedTimeSlot">
        <template v-if="isModalOpened">
            <textBlock
                v-show="durationTextBlockCopy"
                :customText="durationTextBlockCopy"
                justifyText="center"
                typeStyle="small"
                class="duration-text-block" />
            <buttonQuestion
                ref="buttonQuestion"
                v-model="selectedRouteCode"
                buttonTypeString="timeSlotModalListButton"
                :buttonTypeObject="timeSlotModalListButton"
                class="mt-5"
                :answers="availableTimeSlots"
                groupName="chooseTimeSlot"
                textPosition="text-center"
                isRequired
                validationRules="time-slot-required" />
            <div
                v-if="supplementalInformationBlock"
                class="mt-1 mb-2 supplemental-information"
                v-html="supplementalInformationBlock"></div>
            <textBlock
                v-show="disclaimerTextBlockCopy"
                :customText="disclaimerTextBlockCopy"
                justifyText="left"
                typeStyle="caption"
                class="mb-2" />
        </template>
    </modal>
</template>

<script>
// Components
import modal from '@/digital-components/modal/modal.vue';
import textBlock from '@/digital-components/text-block/text-block.vue';
import buttonQuestion from '@/digital-components/button-question/button-question.vue';

// Helpers
import { deepClone } from '@/helpers/object-helper';
import { formatAmountInDollars } from '@/helpers/text-helper';
import { getPriceOfLineItem } from '@/helpers/price-calculator';

// Validation
import { defineRule, useField } from 'vee-validate';
import errorMessages from '@/constants/error-messages';
import { required } from '@/helpers/validation-rules';

// Constants
import {
    AppointmentTypeStrings,
    RouteCodeFlags,
    PREMIUM_TIME_SLOT_ID_FLAG,
    PREMIUM_FEE_PART_TYPE
} from '@/constants/schedule-constants';
import { convertDateStringToDate, getDisplayTextForDurationLength, militaryToTwelveHourTime } from '@/helpers/date-helper';
import timeSlotModalListButton from './time-slot-modal-list-button/time-slot-modal-list-button.vue';

const cmsWidgetFieldMappings = {
    MODAL_CLOSE_BUTTON: 'FooterText',
    SUPPLEMENTAL_INFORMATION: 'BodyText',
    TIME_SLOT_BUTTON: 'HeaderText',
    DISCLAIMER: 'FooterText',
    DURATION: 'SubheaderText'
};

// Validation for the modal button
defineRule('time-slot-required', required(errorMessages.OPTION_REQUIRED));

export default {
    name: 'time-slot-modal-question',
    components: {
        modal,
        textBlock,
        buttonQuestion
    },
    props: {
        modelValue: {
            type: Object,
            default: () => ({
                timeSlot: {
                    routeCode: null,
                    date: null,
                    startTime: null,
                    endTime: null,
                    jobMaxMinutes: null,
                    jobMinMinutes: null
                },
                isPremiumAppointment: null
            })
        },
        cmsWidgetName: String,
        mobileCmsWidgetName: String,
        mobilePremiumCmsWidgetName: String,
        dropoffCmsWidgetName: String,
        sameDayDropOffCmsWidgetName: String,
        overnightDropOffCmsWidgetName: String,
        appointmentType: String,
        timeSlotsForSelectedDate: Object,
        premiumAppointmentFee: Object,
        estimatedServiceMinutesMinimum: Number,
        estimatedServiceMinutesMaximum: Number,
        validationRules: String,
        customComponentId: String,
        selectedDate: String
    },
    emits: ['update:modelValue', 'time-slot-modal-closed', 'timeSlotSelected'],
    setup(props) {
        const uuid = crypto.randomUUID();
        const componentId = !props.customComponentId
            ? `component-${uuid}`
            : props.customComponentId;

        const { modelValue } = deepClone(props);
        const initialValue = modelValue;

        const fieldOptions = {
            value: modelValue,
            initialValue
        };

        const { errorMessage, handleChange, meta, validate, errors } = useField(
            componentId,
            props.validationRules,
            fieldOptions
        );

        return {
            componentId,
            errorMessage,
            handleChange,
            validate,
            meta,
            errors
        };
    },
    data() {
        return {
            isModalOpened: false,
            selectedRouteCode: this.getSelectedRouteCode(),
            timeSlotModalListButton
        };
    },
    computed: {
        modalName() {
            return 'timeSlots';
        },
        modal() {
            return this.$refs[this.modalName];
        },
        supplementalInformationBlock() {
            let appointmentTypeCmsWidgetName;
            if (this.appointmentType === AppointmentTypeStrings.IN_SHOP) {
                return null;
            }

            if (this.appointmentType === AppointmentTypeStrings.MOBILE
                || this.appointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP) {
                appointmentTypeCmsWidgetName = this.selectedRouteCode?.includes(PREMIUM_TIME_SLOT_ID_FLAG)
                    ? this.mobilePremiumCmsWidgetName
                    : this.mobileCmsWidgetName;
            } else {
                if (!this.selectedRouteCode) {
                    return null;
                }
                appointmentTypeCmsWidgetName =
                        this.getRelevantDropOffCmsWidgetNameForSelectedTimeSlot(
                            this.selectedRouteCode,
                            true
                        );
            }

            return this.getCmsContent(
                appointmentTypeCmsWidgetName,
                cmsWidgetFieldMappings.SUPPLEMENTAL_INFORMATION
            );
        },
        footerCloseButtonText() {
            return this.getCmsContent(
                this.cmsWidgetName,
                cmsWidgetFieldMappings.MODAL_CLOSE_BUTTON
            );
        },
        premiumAppointmentButtonText() {
            return this.getCmsContent(
                this.mobilePremiumCmsWidgetName,
                cmsWidgetFieldMappings.TIME_SLOT_BUTTON
            );
        },
        dropoffButtonText() {
            return this.getCmsContent(
                this.dropoffCmsWidgetName,
                cmsWidgetFieldMappings.TIME_SLOT_BUTTON
            );
        },
        sameDayDropoffButtonText() {
            return this.getCmsContent(
                this.sameDayDropOffCmsWidgetName,
                cmsWidgetFieldMappings.TIME_SLOT_BUTTON
            );
        },
        overnightDropoffButtonText() {
            return this.getCmsContent(
                this.overnightDropOffCmsWidgetName,
                cmsWidgetFieldMappings.TIME_SLOT_BUTTON
            );
        },
        dropoffDisclaimerText() {
            return this.getCmsContent(this.dropoffCmsWidgetName, cmsWidgetFieldMappings.DISCLAIMER);
        },
        sameDayDropOffDisclaimerText() {
            return this.getCmsContent(
                this.sameDayDropOffCmsWidgetName,
                cmsWidgetFieldMappings.DISCLAIMER
            );
        },
        overnightDropOffDisclaimerText() {
            return this.getCmsContent(
                this.overnightDropOffCmsWidgetName,
                cmsWidgetFieldMappings.DISCLAIMER
            );
        },
        disclaimerTextBlockCopy() {
            if (this.appointmentType === AppointmentTypeStrings.DROP_OFF) {
                if (this.selectedRouteCode?.includes(RouteCodeFlags.ALL_DAY_DROP_OFF)) {
                    if (this.isSameDay) {
                        return this.sameDayDropOffDisclaimerText;
                    }
                    return this.dropoffDisclaimerText;
                } if (this.selectedRouteCode?.includes(RouteCodeFlags.OVERNIGHT_DROP_OFF)) {
                    return this.overnightDropOffDisclaimerText;
                }
                return null;
            }
            return null;
        },
        dropOffDurationText() {
            return this.getCmsContent(this.dropoffCmsWidgetName, cmsWidgetFieldMappings.DURATION);
        },
        sameDayDropoffDurationText() {
            return this.getCmsContent(
                this.sameDayDropOffCmsWidgetName,
                cmsWidgetFieldMappings.DURATION
            );
        },
        overnightDropoffDurationText() {
            return this.getCmsContent(
                this.overnightDropOffCmsWidgetName,
                cmsWidgetFieldMappings.DURATION
            );
        },
        inshopDurationText() {
            const inshopDurationTextWithoutTime = this.getCmsContent(
                this.cmsWidgetName,
                cmsWidgetFieldMappings.DURATION
            );

            const inshopDurationTime = getDisplayTextForDurationLength(
                this.estimatedServiceMinutesMinimum,
                this.estimatedServiceMinutesMaximum
            );

            return `${inshopDurationTextWithoutTime} ${inshopDurationTime}`;
        },
        durationTextBlockCopy() {
            if (this.appointmentType === AppointmentTypeStrings.MOBILE
                || this.appointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP) {
                return null;
            } if (this.appointmentType === AppointmentTypeStrings.IN_SHOP) {
                return this.inshopDurationText;
            }
            if (this.selectedRouteCode?.includes(RouteCodeFlags.OVERNIGHT_DROP_OFF)) {
                return this.overnightDropoffDurationText;
            } if (this.selectedRouteCode?.includes(RouteCodeFlags.ALL_DAY_DROP_OFF)) {
                if (this.isSameDay) {
                    return this.sameDayDropoffDurationText;
                }
                return this.dropOffDurationText;
            }
            return null;
        },
        isSameDay() {
            if (!this.timeSlotsForSelectedDate) {
                return false;
            }

            const selectedDate = this.timeSlotsForSelectedDate.date;
            const todaysDate = new Date().toISOString().split('T')[0];
            return selectedDate === todaysDate;
        },
        dateSelectedReadableDate() {
            if (!this.timeSlotsForSelectedDate) {
                return null;
            }

            // This conversion ensures we don't get get GMT induced date changes
            const dateObject = convertDateStringToDate(this.timeSlotsForSelectedDate.date);
            // Ex: Tuesday, April 22
            return dateObject.toLocaleDateString('en-us', {
                weekday: 'long',
                month: 'long',
                day: 'numeric'
            });
        },
        availableTimeSlots() {
            if (!this.timeSlotsForSelectedDate) {
                return null;
            }

            if (this.appointmentType === AppointmentTypeStrings.DROP_OFF) {
                return this.getAvailableTimeSlotsForDropOff(this.timeSlotsForSelectedDate.timeSlots);
            } if (this.appointmentType === AppointmentTypeStrings.MOBILE
                    || this.appointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP) {
                return this.getAvailableTimeSlotsForMobile(this.timeSlotsForSelectedDate.timeSlots);
            }
            return this.getAvailableTimeSlotsForInshop(this.timeSlotsForSelectedDate.timeSlots);
        }
    },
    watch: {
        modelValue: {
            handler(newValue) {
                this.handleChange(newValue);
            },
            deep: true
        },
        selectedDate: {
            handler() {
                this.selectedRouteCode = null;
                this.autoSelectTimeSlotIfOnlyOneIsAvailable();
            }
        }
    },
    methods: {
        openModal() {
            this.modal.openModal();
        },
        setModalStatus(isOpened) {
            this.isModalOpened = isOpened;
        },
        closeModal() {
            this.modal.closeModal();
        },
        onModalClosed() {
            this.$emit('time-slot-modal-closed');
        },
        async setSelectedTimeSlot() {
            this.$emit(
                'update:modelValue',
                this.getSelectedTimeSlotInfoObject(this.selectedRouteCode)
            );
            this.$emit('timeSlotSelected');
        },
        getRelevantDropOffCmsWidgetNameForSelectedTimeSlot(
            selectedRouteCode,
            isSameDayRelevant = false
        ) {
            if (selectedRouteCode.includes(RouteCodeFlags.OVERNIGHT_DROP_OFF)) {
                return this.overnightDropOffCmsWidgetName;
            }

            if (selectedRouteCode.includes(RouteCodeFlags.ALL_DAY_DROP_OFF)) {
                return this.isSameDay && isSameDayRelevant
                    ? this.sameDayDropOffCmsWidgetName
                    : this.dropoffCmsWidgetName;
            }

            return '';
        },
        getAvailableTimeSlotsForInshop(timeSlotsForSelectedDate) {
            return timeSlotsForSelectedDate.map((timeSlot) => {
                const readableTime = militaryToTwelveHourTime(timeSlot.startTime);
                return {
                    value: timeSlot.id,
                    buttonLabel: readableTime
                };
            });
        },
        getAvailableTimeSlotsForDropOff(timeSlotsForSelectedDate) {
            const availableTimeSlots = timeSlotsForSelectedDate.map((timeSlot) => {
                let buttonLabelValue;
                if (timeSlot.id.includes(RouteCodeFlags.OVERNIGHT_DROP_OFF)) {
                    buttonLabelValue = this.overnightDropoffButtonText;
                } else if (this.isSameDay) {
                    buttonLabelValue = this.sameDayDropoffButtonText;
                } else {
                    buttonLabelValue = this.dropoffButtonText;
                }

                return {
                    value: timeSlot.id,
                    buttonLabel: buttonLabelValue
                };
            });

            return availableTimeSlots;
        },
        getAvailableTimeSlotsForMobile(timeSlotsForSelectedDate) {
            const availableTimeSlots = timeSlotsForSelectedDate.map((timeSlot) => {
                const readableTime = `${militaryToTwelveHourTime(timeSlot.startTime)} - ${militaryToTwelveHourTime(timeSlot.endTime)}`;
                return {
                    value: timeSlot.id,
                    buttonLabel: readableTime
                };
            });

            const isPremiumTimeSlot = timeSlotsForSelectedDate[0].offerPremium;
            const hasPremiumPartAvailable =
                this.premiumAppointmentFee?.partType === PREMIUM_FEE_PART_TYPE;
            if (isPremiumTimeSlot && hasPremiumPartAvailable) {
                availableTimeSlots.unshift(this.getPremiumAppointmentTimeSlot(timeSlotsForSelectedDate[0]));
            }

            return availableTimeSlots;
        },
        getPremiumAppointmentTimeSlot(timeSlotData) {
            const formattedPrice =
                `+${formatAmountInDollars(getPriceOfLineItem(this.premiumAppointmentFee))}`;

            return {
                // Unique value is required for each <input> and the premium appoinment shares an id
                value: this.addPremiumFlagToInput(timeSlotData.id),
                buttonLabel: this.premiumAppointmentButtonText,
                buttonLabelSubCopy: formattedPrice,
                additionalButtonData: {
                    isPremiumAppointment: true
                }
            };
        },
        getSelectedRouteCode() {
            let selectedRouteCode;
            if (!this.modelValue?.timeSlot) {
                selectedRouteCode = null;
            }

            if (this.modelValue?.isPremiumAppointment) {
                selectedRouteCode = this.addPremiumFlagToInput(this.modelValue?.timeSlot?.routeCode);
            } else {
                selectedRouteCode = this.modelValue?.timeSlot?.routeCode;
            }

            return selectedRouteCode;
        },
        autoSelectTimeSlotIfOnlyOneIsAvailable() {
            const numberOfOptions = this.availableTimeSlots?.length;
            if (numberOfOptions === 1) {
                this.selectedRouteCode = this.availableTimeSlots[0].value;
            }
        },
        addPremiumFlagToInput(routeCode) {
            return (`${routeCode}${PREMIUM_TIME_SLOT_ID_FLAG}`);
        },
        removePremiumFlagFromInput(routeCode) {
            return routeCode.replace(PREMIUM_TIME_SLOT_ID_FLAG, '');
        },
        getSelectedTimeSlotInfoObject(routeCode) {
            let routeCodeToUse = routeCode;
            const routeCodeIncludesPremium = routeCode?.includes(PREMIUM_TIME_SLOT_ID_FLAG);
            if (routeCodeIncludesPremium) {
                routeCodeToUse = this.removePremiumFlagFromInput(routeCode);
            }

            const timeSlot = this.timeSlotsForSelectedDate?.timeSlots?.find((ts) => ts.id === routeCodeToUse);

            if (timeSlot) {
                return {
                    timeSlot: {
                        date: this.timeSlotsForSelectedDate.date,
                        routeCode: timeSlot.id,
                        startTime: timeSlot.startTime,
                        endTime: timeSlot.endTime,
                        jobMaxMinutes: this.estimatedServiceMinutesMaximum.toString(),
                        jobMinMinutes: this.estimatedServiceMinutesMinimum.toString()
                    },
                    isPremiumAppointment: !!routeCodeIncludesPremium
                };
            }

            return {
                timeSlot: {
                    date: null,
                    startTime: null,
                    endTime: null,
                    routeCode: null,
                    jobMaxMinutes: null,
                    jobMinMinutes: null
                },
                isPremiumAppointment: null
            };
        }
    }
};
</script>

<style lang="scss">
.time-slots-modal.modal.modal-component {
    .modal-header {
        padding-bottom: 0;
        margin-bottom: 0 !important;
    }
    .text-block.duration-text-block {
        margin-top: 4px !important;
    }
    .supplemental-information {
        line-height: 1.5rem;
        font-size: 0.875rem;
        li strong {
            font-weight: $font-weight-bold;
        }
        li:not(:last-child) {
            margin-bottom: 8px;
        }
    }
}
</style>
