<template>
    <modal
        :ref="modalName"
        :headerText="dateSelectedReadableDate"
        :footerButtonText="footerCloseButtonText"
        :onModalClosedCallback="onModalClosed"
        @isModalOpened="setModalStatus"
        @footer-button-event="setSelectedTimeSlot"
        class="time-slots-modal">
        <template v-if="isModalOpened">
            <textBlock
                v-show="durationTextBlockCopy"
                :customText="durationTextBlockCopy"
                justifyText="center"
                typeStyle="small"
                class="duration-text-block" />
            <buttonQuestion
                ref="buttonQuestion"
                buttonTypeString="timeSlotModalListButton"
                :buttonTypeObject="timeSlotModalListButton"
                class="mt-5"
                :answers="availableTimeSlots"
                groupName="chooseTimeSlot"
                textPosition="text-center"
                v-model="selectedTimeSlotId"
                isRequired
                validationRules="time-slot-required" />
            <div
                class="mt-1 mb-2 supplemental-information"
                v-if="supplementalInformationBlock"
                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";
import textBlock from "@/digital-components/text-block/text-block";
import buttonQuestion from "@/digital-components/button-question/button-question";
import timeSlotModalListButton from "./time-slot-modal-list-button/time-slot-modal-list-button";

// Helpers
import {
    convertDateStringToDate,
    militaryToTwelveHourTime,
    getDisplayTextForDurationLength,
} from "@/layouts/schedule/helpers/schedule-helper";
import { deepClone } from "@/helpers/object-helper";

// Validation - TODO: Move this somewhere more global?
import { defineRule, useField } from "vee-validate";
import { errorMessages } from "@/constants/error-messages";
import { required } from "@/helpers/validation-rules";

import { v4 as uuidv4 } from "uuid";

// Constants
import {
    AppointmentTypeStrings,
    RouteCodeFlags,
    PREMIUM_TIME_SLOT_ID_FLAG,
    PREMIUM_FEE_PART_TYPE,
} from "@/constants/schedule-constants";

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",
    emits: ["update:modelValue"],
    props: {
        modelValue: {
            type: Object,
            default: () => ({
                routeCode: null,
                date: null,
                startTime: null,
                endTime: null,
                jobMaxMinutes: null,
                jobMinMinutes: null,
            }),
        },
        cmsWidgetName: String,
        mobileCmsWidgetName: String,
        mobilePremiumCmsWidgetName: String,
        dropoffCmsWidgetName: String,
        sameDayDropOffCmsWidgetName: String,
        overnightDropOffCmsWidgetName: String,
        appointmentType: String,
        dateAndTimeSlotData: Object,
        premiumAppointmentFee: Object,
        estimatedServiceMinutesMinimum: Number,
        estimatedServiceMinutesMaximum: Number,
        validationRules: String,
        customComponentId: String,
        selectedDate: String,
    },
    data() {
        return {
            isModalOpened: false,
            selectedValue: null,
            timeSlotModalListButton: timeSlotModalListButton,
        };
    },
    setup(props) {
        const uuid = uuidv4();
        const componentId = !props.customComponentId
            ? `component-${uuid}`
            : props.customComponentId;

        const modelValue = deepClone(props).modelValue;
        const initialValue = modelValue;

        const fieldOptions = {
            value: modelValue,
            initialValue: initialValue,
        };

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

        return {
            componentId,
            errorMessage,
            handleChange,
            validate,
            meta,
            errors,
        };
    },
    computed: {
        modalName() {
            return "timeSlots";
        },
        selectedTimeSlotId: {
            get: function () {
                return this.modelValue?.routeCode;
            },
            set: function (newValue) {
                // Button Question only supports Number, or String data types so we must convert to the full object before emitting
                this.selectedValue = this.getSelectedTimeSlotObject(newValue);
            },
        },
        supplementalInformationBlock() {
            let appointmentTypeCmsWidgetName;
            if (this.appointmentType === AppointmentTypeStrings.IN_SHOP) {
                return null;
            } else if (this.appointmentType === AppointmentTypeStrings.MOBILE) {
                appointmentTypeCmsWidgetName = this.selectedTimeSlotId?.includes(
                    PREMIUM_TIME_SLOT_ID_FLAG
                )
                    ? this.mobilePremiumCmsWidgetName
                    : this.mobileCmsWidgetName;
            } else {
                if (!this.selectedTimeSlotId) {
                    return null;
                } else {
                    appointmentTypeCmsWidgetName =
                        this.getRelevantDropOffCmsWidgetNameForSelectedTimeSlot(
                            this.selectedTimeSlotId,
                            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.selectedTimeSlotId?.includes(RouteCodeFlags.ALL_DAY_DROP_OFF)) {
                    if (this.isSameDay) {
                        return this.sameDayDropOffDisclaimerText;
                    } else {
                        return this.dropoffDisclaimerText;
                    }
                } else if (this.selectedTimeSlotId?.includes(RouteCodeFlags.OVERNIGHT_DROP_OFF)) {
                    return this.overnightDropOffDisclaimerText;
                } else {
                    return null;
                }
            } else {
                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) {
                return null;
            } else if (this.appointmentType === AppointmentTypeStrings.IN_SHOP) {
                return this.inshopDurationText;
            } else {
                if (this.selectedTimeSlotId?.includes(RouteCodeFlags.OVERNIGHT_DROP_OFF)) {
                    return this.overnightDropoffDurationText;
                } else if (this.selectedTimeSlotId?.includes(RouteCodeFlags.ALL_DAY_DROP_OFF)) {
                    if (this.isSameDay) {
                        return this.sameDayDropoffDurationText;
                    } else {
                        return this.dropOffDurationText;
                    }
                } else {
                    return null;
                }
            }
        },
        isSameDay() {
            if (!this.dateAndTimeSlotData) {
                return false;
            }

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

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

            if (this.appointmentType === AppointmentTypeStrings.DROP_OFF) {
                return this.getAvailableTimeSlotsForDropOff(this.dateAndTimeSlotData.timeSlots);
            } else if (this.appointmentType === AppointmentTypeStrings.MOBILE) {
                return this.getAvailableTimeSlotsForMobile(this.dateAndTimeSlotData.timeSlots);
            } else {
                return this.getAvailableTimeSlotsForInshop(this.dateAndTimeSlotData.timeSlots);
            }
        },
        modal() {
            return this.$refs[this.modalName];
        },
    },
    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.selectedValue);
            this.closeModal();
        },
        getRelevantDropOffCmsWidgetNameForSelectedTimeSlot(
            selectedTimeSlotId,
            isSameDayRelevant = false
        ) {
            if (selectedTimeSlotId.includes(RouteCodeFlags.OVERNIGHT_DROP_OFF)) {
                return this.overnightDropOffCmsWidgetName;
            } else if (selectedTimeSlotId.includes(RouteCodeFlags.ALL_DAY_DROP_OFF)) {
                return this.isSameDay && isSameDayRelevant
                    ? this.sameDayDropOffCmsWidgetName
                    : this.dropoffCmsWidgetName;
            }
        },
        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 =
                "+$" + this.getTotalLineItemPrice(this.premiumAppointmentFee).toFixed(2);
            return {
                // Unique value is required for each <input> and the premium appoinment shares a timeSlot ID
                value: this.addPremiumFlagToInput(timeSlotData.id),
                buttonLabel: this.premiumAppointmentButtonText,
                buttonLabelSubCopy: formattedPrice,
                additionalButtonData: {
                    isPremiumAppointment: true,
                },
            };
        },
        autoSelectTimeSlotIfOnlyOneIsAvailable(newAvailableTimeSlotsValue) {
            const numberOfOptions = newAvailableTimeSlotsValue?.length;
            if (numberOfOptions === 1) {
                this.selectedTimeSlotId = newAvailableTimeSlotsValue[0].value;
            }
        },
        addPremiumFlagToInput(timeSlotId) {
            return (timeSlotId += PREMIUM_TIME_SLOT_ID_FLAG);
        },
        removePremiumFlagFromInput(timeSlotId) {
            return timeSlotId.substring(0, timeSlotId.length - PREMIUM_TIME_SLOT_ID_FLAG.length);
        },
        getSelectedTimeSlotObject(timeSlotId) {
            const timeSlot = this.dateAndTimeSlotData?.timeSlots?.find(
                (timeSlot) => timeSlot.id == timeSlotId
            );

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

            return {
                date: null,
                startTime: null,
                endTime: null,
                routeCode: null,
                jobMaxMinutes: null,
                jobMinMinutes: null,
            };
        },
    },
    watch: {
        modelValue: {
            handler(newValue) {
                this.handleChange(newValue);
            },
            deep: true,
        },
        selectedDate: {
            handler() {
                this.selectedTimeSlotId = null;
            },
        },
        availableTimeSlots(newValue) {
            this.autoSelectTimeSlotIfOnlyOneIsAvailable(newValue);
        },
    },
    components: {
        modal,
        textBlock,
        buttonQuestion,
    },
};
</script>

<style lang="scss">
.time-slots-modal.modal.modal-component {
    > .modal-dialog > .modal-content {
        margin-top: 24px;
    }
    .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>
