<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="selectedRouteCode"
                isRequired
                validationRules="time-slot-required" />
            <div
                v-if="hasWaitListExperiment && displayWaitListFeature"
                class="mt-5 bg-light rounded waitlist">
                <textBlock
                    cmsWidgetName="WaitListLabelWidget"
                    typeStyle="medium"
                    fontWeight="600"
                    marginTopSizeOverride="0" />
                <checkboxQuestion
                    class="mt-3"
                    cmsWidgetName="WaitListQuestionWidget"
                    v-model="waitListRequested"
                    @click="waitListChecked" />
            </div>
            <div
                v-if="waitListRequested"
                class="mt-5 rounded waitlist-success"
                ref="waitlistSuccessMessage">
                <img :src="waitListSuccessImage" class="success-image" />
                <span v-html="waitListSuccessText" class="success-text"></span>
            </div>
            <div
                class="mt-5 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 checkboxQuestion from "@/digital-components/checkbox-question/checkbox-question";
import timeSlotModalListButton from "./time-slot-modal-list-button/time-slot-modal-list-button";
import experimentMixin from "@/mixins/experiment-mixin";
import { experimentSettings } from "@/constants/experiments";
import store from "@/store";

// Helpers
import { deepClone } from "@/helpers/object-helper";
import {
    convertDateStringToDate,
    militaryToTwelveHourTime,
} from "@/layouts/schedule/helpers/schedule-helper";
import { getDisplayTextForDurationLength } from "@/helpers/duration-length-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", "TimeSlotSelected", "click-event"],
    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,
        displayWaitList: Boolean,
    },
    data() {
        return {
            isModalOpened: false,
            selectedRouteCode: this.getSelectedRouteCode(),
            timeSlotModalListButton: timeSlotModalListButton,
            waitListRequested: this.getWaitListRequestedFromStore(),
        };
    },
    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";
        },
        modal() {
            return this.$refs[this.modalName];
        },
        supplementalInformationBlock() {
            let appointmentTypeCmsWidgetName;
            if (this.appointmentType === AppointmentTypeStrings.IN_SHOP) {
                return null;
            } else if (this.appointmentType === AppointmentTypeStrings.MOBILE) {
                appointmentTypeCmsWidgetName = this.selectedRouteCode?.includes(
                    PREMIUM_TIME_SLOT_ID_FLAG
                )
                    ? this.mobilePremiumCmsWidgetName
                    : this.mobileCmsWidgetName;
            } else {
                if (!this.selectedRouteCode) {
                    return null;
                } else {
                    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;
                    } else {
                        return this.dropoffDisclaimerText;
                    }
                } else if (this.selectedRouteCode?.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.selectedRouteCode?.includes(RouteCodeFlags.OVERNIGHT_DROP_OFF)) {
                    return this.overnightDropoffDurationText;
                } else if (this.selectedRouteCode?.includes(RouteCodeFlags.ALL_DAY_DROP_OFF)) {
                    if (this.isSameDay) {
                        return this.sameDayDropoffDurationText;
                    } else {
                        return this.dropOffDurationText;
                    }
                } else {
                    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
                );
            } else if (this.appointmentType === AppointmentTypeStrings.MOBILE) {
                return this.getAvailableTimeSlotsForMobile(this.timeSlotsForSelectedDate.timeSlots);
            } else {
                return this.getAvailableTimeSlotsForInshop(this.timeSlotsForSelectedDate.timeSlots);
            }
        },
        hasWaitListExperiment() {
            return experimentMixin.methods.hasSettingEqualTo(
                experimentSettings.DISPLAY_WAITLIST,
                "true"
            );
        },
        displayWaitListFeature() {
            return this.displayWaitList;
        },
        waitListSuccessImage() {
            return this.getCmsContent("WaitListSuccessWidget", "Image");
        },
        waitListSuccessText() {
            return this.getCmsContent("WaitListSuccessWidget", "BodyText");
        },
    },
    methods: {
        openModal() {
            this.modal.openModal();
        },
        setModalStatus(isOpened) {
            this.isModalOpened = isOpened;
        },
        closeModal() {
            this.modal.closeModal();
        },
        onModalClosed() {
            this.$emit("time-slot-modal-closed");
            this.selectedRouteCode = this.getSelectedRouteCode();
            this.modal.resetForm();
        },
        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;
            } else if (selectedRouteCode.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 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;
        },
        getWaitListRequestedFromStore() {
            return store.getters.order.customer?.waitListRequested;
        },
        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) {
            const routeCodeIncludesPremium = routeCode?.includes(PREMIUM_TIME_SLOT_ID_FLAG);
            if (routeCodeIncludesPremium) {
                routeCode = this.removePremiumFlagFromInput(routeCode);
            }

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

            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 ? true : false,
                };
            }

            return {
                timeSlot: {
                    date: null,
                    startTime: null,
                    endTime: null,
                    routeCode: null,
                    jobMaxMinutes: null,
                    jobMinMinutes: null,
                },
                isPremiumAppointment: null,
            };
        },
        waitListChecked(event) {
            this.$emit("waitListRequested", event.target.checked);
        },
        scrollToSuccessMessage() {
            const successMessageElement = this.$refs.waitlistSuccessMessage;
            if (successMessageElement) {
                successMessageElement.scrollIntoView({ behavior: "smooth" });
            }
        },
    },
    unmounted() {
        if (this.isModalOpened) this.closeModal();
    },
    watch: {
        waitListRequested(newVal) {
            if (newVal) {
                this.$nextTick(() => {
                    this.scrollToSuccessMessage();
                });
            }
        },
        modelValue: {
            handler(newValue) {
                this.handleChange(newValue);
            },
            deep: true,
        },
        selectedDate: {
            handler() {
                this.selectedRouteCode = null;
                this.autoSelectTimeSlotIfOnlyOneIsAvailable();
            },
        },
    },
    components: {
        modal,
        textBlock,
        buttonQuestion,
        checkboxQuestion,
    },
};
</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;
        }
    }
    .waitlist {
        box-shadow: 0px 1px 4px 0px #00000033;
        border-radius: 8px;
        font-size: $h6-font-size;
        padding: 16px;
        margin-top: 16px;
        margin-bottom: -8px;
        .ui-checkbox {
            padding-left: 0px;
            input {
                border-radius: 4px;
                box-shadow: 0px 1px 4px 0px #00000033;
            }
        }
        .form-check-input {
            margin-left: 0px;
        }
    }
    .waitlist-success {
        background-color: #ecf5e9;
        display: flex;
        align-items: flex-start;
        border: 1px solid #0c7e47;
        border-radius: 5px;
        font-size: $h5-font-size;
        padding: 0.75rem 1rem;
        margin-bottom: -0.5rem;
        .success-text {
            margin-left: 0.5rem;
            strong {
                font-weight: 600;
                letter-spacing: 0%;
            }
        }
        .success-image {
            margin-top: 4.5px;
            width: 1rem;
            height: 1rem;
            color: #0c7e47;
        }
    }
}
</style>
