<template>
    <div
        class="date-picker text-center"
        :class="[calendarViewDirection, { 'has-error': errors.length > 0 }]">
        <fieldset
            id="date-picker-fieldset"
            ref="datePickerFieldset">
            <legend class="sr-only">
                Select a day and time
            </legend>
            <div
                v-for="month in months"
                :id="`${month.monthLabel}-${month.yearNum?.toString()}`"
                :key="`${month.monthLabel}-${month.yearNum?.toString()}`"
                class="calendar-grid-container"
                :class="[
                    hideSomeDaysForInitialView ? 'partial-month-initial-view' : '',
                    month.monthClass,]">
                <div class="month-year body-small d-flex align-items-center small">
                    {{ month.monthLabel }} {{ month.yearNum?.toString() }}
                </div>
                <div
                    v-if="calendarViewDirection === 'future'"
                    class="legend caption d-flex align-items-center justify-content-end">
                    <span class="legend-circle me-1"></span> &equals; Available
                </div>
                <div class="separator-line"></div>
                <div class="nav-back ps-3">
                    <button></button>
                </div>
                <div class="nav-forward pe-3">
                    <button></button>
                </div>
                <div class="grid-item caption">
                    <span class="sr-only">Sunday</span>S
                </div>
                <div class="grid-item caption">
                    <span class="sr-only">Monday</span>M
                </div>
                <div class="grid-item caption">
                    <span class="sr-only">Tuesday</span>T
                </div>
                <div class="grid-item caption">
                    <span class="sr-only">Wednesday</span>W
                </div>
                <div class="grid-item caption">
                    <span class="sr-only">Thursday</span>T
                </div>
                <div class="grid-item caption">
                    <span class="sr-only">Friday</span>F
                </div>
                <div class="grid-item caption">
                    <span class="sr-only">Saturday</span>S
                </div>
                <div
                    v-for="date in month.dates"
                    :id="date.inputValue"
                    :key="date.inputValue"
                    class="grid-item radio-wrapper"
                    :class="[
                        date.dateNum === 1 ? 'first-day-' + month.startDateDayIndex : '',
                        date.dayClasses,
                        date.isSelectable ? 'selectable-day' : '',]">
                    <input
                        :id="`${month.monthLabel}-${date.dateNum.toString()}`"
                        v-model="selectedDate"
                        :disabled="!date.isSelectable"
                        type="radio"
                        name="day-of-month"
                        :value="date.inputValue"
                        @click="fireDateSelectedEvent"
                        @keypress.enter="fireDateSelectedEvent" />
                    <label :for="`${month.monthLabel}-${date.dateNum.toString()}`">
                        <span>{{ date.dateNum.toString() }}</span>
                    </label>
                </div>
            </div>
            <loader
                :class="[!isLoading ? 'date-picker-hidden' : '']"
                loaderColor="blue"
                loaderPosition="center" />
            <div
                id="date-of-month-error"
                class="row form-test-error">
                <ErrorMessage
                    :name="customComponentId"
                    class="small mt-1">
                </ErrorMessage>
            </div>
            <button
                v-if="calendarViewDirection === 'future' && !disableViewMoreDatesButton"
                id="viewMoreDates"
                type="button"
                class="btn btn-link"
                :disabled="isLoading"
                @click="showAnotherMonth">
                View more dates
            </button>
        </fieldset>
    </div>
</template>

<script>
// Supporting files
import loader from '@/ux-components/loader/loader.vue';
import { useMainStore } from '@/store';
import { useField, ErrorMessage } from 'vee-validate';
import { deepClone } from '@/helpers/object-helper';
import {
    convertDateToDateString,
    convertDateStringToDate
} from '@/layouts/schedule-page/helpers/schedule-helper';
import { TIMINGFUNC_MAP, BUFFER_OFFSET, MONTHS_OF_YEAR } from './mixins/constants';
import { selectableDaysOptions, requiredParameter } from './mixins/helpers';

export default {
    name: 'date-picker',
    components: {
        loader,
        ErrorMessage
    },
    props: {
        customComponentId: String,
        selectableDatesSetting: {
            type: String,
            validator(value) {
                return Object.values(selectableDaysOptions).includes(value);
            },
            default: selectableDaysOptions.PAST
        },
        modelValue: {
            type: Object
        },
        todayOverrideDateString: {
            // keep for use in unit tests to override today's date
            type: String,
            default: null
        },
        customSelectableDatesCallback: {
            type: Function,
            default() {
                return [];
            }
        },
        validationRules: {
            type: String,
            default: ''
        }
    },
    emits: ['update:modelValue', 'date-clicked'],
    setup(props) {
        const uuid = crypto.randomUUID();
        const componentId = !props.customComponentId
            ? `component-${uuid}`
            : props.customComponentId;

        const mainStore = useMainStore();

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

        const fieldOptions = {
            value: modelValue,
            initialValue
        };

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

        return {
            componentId,
            mainStore,
            errorMessage,
            handleBlur,
            handleChange,
            validate,
            meta,
            errors,
            resetField
        };
    },
    data() {
        return {
            isLoading: true,
            months: null,
            disableViewMoreDatesButton: false,
            selectableDatesData: [], // NOTE: uses monthNum (1-based), NOT monthIndex (0-based)
            hideSomeDaysForInitialView: null
        };
    },
    computed: {
        todayString() {
            return this.todayOverrideDateString || convertDateToDateString(new Date());
        },
        todayDayIndex() {
            return convertDateStringToDate(this.todayString).getDay();
        },
        todayDateNum() {
            return convertDateStringToDate(this.todayString).getDate();
        },
        currentWeekStartDateNum() {
            return this.todayDayIndex >= this.todayDateNum
                ? 1
                : this.todayDateNum - this.todayDayIndex;
        },
        currentWeekEndDateNum() {
            return this.todayDateNum + (6 - this.todayDayIndex);
        },
        calendarViewDirection() {
            if (this.selectableDatesSetting === 'custom') return 'future';
            return 'past';
        },
        selectedDate: {
            get() {
                return this.modelValue;
            },
            set(newSelectedDate) {
                this.$emit('update:modelValue', newSelectedDate);
            }
        }
    },
    watch: {
        modelValue(newValue, oldValue) {
            this.resetField({
                value: newValue
            });
        },
        errorMessage(newValue, oldValue) {
            // Check for changing from no error message to some error message.
            if (newValue && !oldValue) {
                this.scrollToElement('date-of-month-error');
            }
        }
    },
    methods: {
        initializeComponent(initialData) {
            this.setCalendarData(initialData);
        },
        fireDateSelectedEvent(event) {
            // Ignore if arrow key selected radioButton
            if (event.screenX === 0 && event.screenY === 0) {
                return;
            }
            this.$emit('date-clicked');
        },
        getWeekStartDate(dateString) {
            const date = convertDateStringToDate(dateString);
            const dayOfWeek = date.getDay();
            // Subtract the day of the week from date to get the date of Sunday
            const sunday = new Date(date);
            sunday.setDate(sunday.getDate() - dayOfWeek);
            return convertDateToDateString(sunday);
        },
        getWeekEndDate(dateString) {
            const date = convertDateStringToDate(dateString);
            const dayOfWeek = date.getDay();
            const daysUntilSaturday = 6 - dayOfWeek; // Calculate the number of days until Saturday
            // Clone the given date and add the remaining days until Saturday
            const saturday = new Date(date);
            saturday.setDate(date.getDate() + daysUntilSaturday);
            return convertDateToDateString(saturday);
        },
        getNextWeekSunday(dateString) {
            const date = convertDateStringToDate(dateString);
            const dayOfWeek = date.getDay();
            const daysUntilNextSunday = 7 - dayOfWeek; // Calculate the number of days until the next Sunday
            // Clone the given date and add the remaining days until Sunday
            const nextSunday = new Date(date);
            nextSunday.setDate(date.getDate() + daysUntilNextSunday);
            return convertDateToDateString(nextSunday);
        },
        getMonthEnd(dateStr) {
            // convert string to date, do date calc, then return a string back
            const date = new Date(dateStr.split('-')[0], parseInt(dateStr.split('-')[1], 10), 0);
            return convertDateToDateString(date);
        },
        getInitialViewWeeks(todayString, initialViewRowsToShow, preSelectedDateString) {
            // TODO: this only is for future direction; need to create logic for past direction
            const weeks = [];
            let weekStartDate = this.getWeekStartDate(todayString);
            let weekEndDate = this.getWeekEndDate(todayString);

            if (preSelectedDateString) {
                const preSelectedDateMonthEnd = this.getMonthEnd(preSelectedDateString);
                let weekIncludesPreSelectedMonthEnd = false;
                let i = 0;
                while (!weekIncludesPreSelectedMonthEnd) {
                    if (i > 0) {
                        weekStartDate = this.getNextWeekSunday(weekEndDate);
                        weekEndDate = this.getWeekEndDate(weekStartDate);

                        if (
                            (preSelectedDateMonthEnd > weekStartDate
                                && preSelectedDateMonthEnd < weekEndDate)
                            || preSelectedDateMonthEnd === weekStartDate
                            || preSelectedDateMonthEnd === weekEndDate
                        ) {
                            weekEndDate = preSelectedDateMonthEnd;
                            weekIncludesPreSelectedMonthEnd = true;
                        }
                    }
                    weeks.push({
                        weekNum: i + 1,
                        weekStartDate,
                        weekEndDate
                    });
                    i++;
                }
            } else {
                for (let i = 0; i < initialViewRowsToShow; i++) {
                    if (i > 0) {
                        weekStartDate = this.getNextWeekSunday(weekEndDate);
                        weekEndDate = this.getWeekEndDate(weekStartDate);
                    }
                    weeks.push({
                        weekNum: i + 1,
                        weekStartDate,
                        weekEndDate
                    });
                }
                // If any of these weeks is split between two months, then make them 2 separate "weeks"
                // (a week split between two months is considered 2 weeks per business requirements)
                const hasSplitWeek = (week) => (week.weekStartDate.split('-')[1] !== week.weekEndDate.split('-')[1]);
                const splitWeekIndex = weeks.findIndex(hasSplitWeek);

                if (splitWeekIndex > -1) {
                    const week1 = [];
                    const week2 = [];
                    let switchToWeek2 = false;

                    for (let j = 0; j < 7; j++) {
                        const newDate = convertDateStringToDate(weeks[splitWeekIndex].weekStartDate);
                        newDate.setDate(newDate.getDate() + j);
                        if (newDate.getDate() === 1) switchToWeek2 = true;
                        if (switchToWeek2) {
                            week2.push(convertDateToDateString(newDate));
                        } else {
                            week1.push(convertDateToDateString(newDate));
                        }
                    }

                    const week1EndDate = week1[week1.length - 1];
                    const week2StartDate = week2[0];

                    if (week1EndDate < todayString) {
                        // replace week 1 with week 2
                        weeks[splitWeekIndex].weekStartDate = week2StartDate;
                    } else {
                        const newWeek = {
                            weekNum: weeks[splitWeekIndex].weekNum,
                            weekStartDate: week2StartDate,
                            weekEndDate: weeks[splitWeekIndex].weekEndDate
                        };
                        weeks[splitWeekIndex].weekEndDate = week1EndDate;
                        weeks.splice(splitWeekIndex + 1, 0, newWeek);
                        weeks.pop();
                        weeks.forEach((item, index) => {
                            if (index > splitWeekIndex) {
                                item.weekNum += 1;
                            }
                        });
                    }
                }
            }
            return weeks;
        },
        async loadInitialData(config) {
            /*
             ** NOTE: this _could_ be called by a parent before fully loaded, so data or computeds might not be available
             */
            let todayDateString;
            let calendarViewDirection = 'none';
            let hideSomeDaysForInitialView = false;
            let hideSecondMonth = false;

            if (this.todayString) {
                todayDateString = this.todayString;
            } else if (config.todayOverrideDateString) {
                todayDateString = config.todayOverrideDateString;
            } else {
                todayDateString = convertDateToDateString(new Date());
            }
            if (config.selectableDatesSetting === 'past') calendarViewDirection = 'past';
            if (config.selectableDatesSetting === 'custom') calendarViewDirection = 'future';

            const currentMonthEnd = this.getMonthEnd(todayDateString);
            // TODO - set up currentMonthStart if direction is PAST:
            // let currentMonthStart = new Date(todayYearNum, todayMonthIndex - 1, 1);
            const initialViewWeeks = this.getInitialViewWeeks(
                todayDateString,
                config.initialViewRowsToShow,
                config.preSelectedDate
            );
            const initialViewStartDate = todayDateString;
            const initialViewEndDate = initialViewWeeks[initialViewWeeks.length - 1].weekEndDate;

            if (!config.preSelectedDate) {
                const firstSaturdayMonth = initialViewWeeks[0].weekEndDate.split('-')[1];
                const lastSundayMonth =
                    initialViewWeeks[initialViewWeeks.length - 1].weekStartDate.split('-')[1];

                if (calendarViewDirection === 'future') {
                    if (firstSaturdayMonth !== lastSundayMonth) {
                        hideSomeDaysForInitialView = true;
                    }
                    if (initialViewStartDate.split('-')[1] === lastSundayMonth) {
                        hideSecondMonth = true;
                        if (currentMonthEnd > initialViewEndDate) {
                            // should part of 1st month be hidden?
                            hideSomeDaysForInitialView = true;
                        }
                    }
                }
                // TODO - NEED TO CREATE OPPOSITE LOGIC FOR "past" DIRECTION LIKE THE ABOVE ^ ^ ^
            }

            const loadInitialDataPromise = new Promise((resolve, reject) => {
                const response = config.customSelectableDatesCallback(
                    initialViewStartDate,
                    initialViewEndDate,
                    useMainStore().order.serviceLocation.appointmentType,
                    useMainStore().order.serviceLocation.provider.providerNumber
                );
                resolve(response);
            });

            return loadInitialDataPromise.then((response) => {
                const initialData = {
                    todayDate: todayDateString,
                    initialViewStartDate,
                    initialViewEndDate,
                    calendarViewDirection,
                    initialShopTimeSlotsResponse: response,
                    hideSomeDaysForInitialView,
                    hideSecondMonth,
                    preSelectedDate: config.preSelectedDate
                };
                return initialData;
            });
        },
        async setCalendarData(config = {}) {
            this.hideSomeDaysForInitialView = config.hideSomeDaysForInitialView;
            const { hideSecondMonth } = config;
            const direction = config.calendarViewDirection;
            const monthsAfterToLoadOffset = 6;
            const monthsBeforeToLoadOffset = 36;
            config.initialShopTimeSlotsResponse.days.forEach((selectableDate) => {
                this.selectableDatesData.push(selectableDate);
            });

            // GENERATE MONTHS AND PUSH THEM INTO ARRAY
            const months = [];
            const options = {
                calendarViewDirection: direction,
                monthsBeforeToLoadOffset,
                monthsAfterToLoadOffset,
                initialViewStartDate: config.initialViewStartDate,
                initialViewEndDate: config.initialViewEndDate,
                hideSecondMonth,
                preSelectedDate: config.preSelectedDate
            };
            if (direction === 'future') {
                // first 0, then 1
                for (let i = 0; i <= monthsAfterToLoadOffset; i++) {
                    months.push(this.getMonthData(i, options));
                }
                // See https://eslint.org/docs/latest/rules/no-await-in-loop
                Promise.all(months);
            } else if (direction === 'past') {
                // first 0, then -1
                for (let i = 0; i >= 0 - monthsBeforeToLoadOffset; i--) {
                    months.unshift(this.getMonthData(i, options));
                }
                Promise.all(months);
            } else {
                // TODO - IF A CALENDAR WITH BOTH PAST AND FUTURE WAS EVER NEEDED
                // for (let i = monthsAfterToLoadOffset; i >= monthsBeforeToLoadOffset; i--) {
                //     months.push(this.getMonthDataPAST(i));
                // }
            }
            this.months = months;
            this.isLoading = false;

            if (config.preSelectedDate) {
                this.$nextTick(() => {
                    // Advance to month
                    const monthToShow = this.months.find((month) =>
                        month.monthClass.includes('month-preselected'));
                    if (
                        monthToShow.monthClass.includes('month-preselected')
                        && monthToShow.monthClass.includes('last-available-month')
                    ) {
                        // disable View More dates button if the preSelectedDate in the last available month
                        this.disableViewMoreDatesButton = true;
                    }
                    this.scrollToElement(monthToShow.monthString);
                });
            }
        },
        async getMonthData(offset = requiredParameter(), options) {
            /*  options will contain:
                    calendarViewDirection (string)
                    initialViewStartDateNum (number)
                    initialViewEndDateNum (number)
                    monthsBeforeToLoadOffset (number),
                    monthsAfterToLoadOffset (number),
                    hideSecondMonth (boolean),
                    preSelectedDate (string)

                data used:
                    todayDate (date object)
                    this.hideSomeDaysForInitialView (string)
            */

            let monthNum = convertDateStringToDate(this.todayString).getMonth() + offset + 1;
            let yearNum = convertDateStringToDate(this.todayString).getFullYear();
            const { calendarViewDirection } = options;
            if (calendarViewDirection === 'future' && offset > 0) {
                while (monthNum > 12) {
                    monthNum -= 12;
                    yearNum++;
                }
            } else if (calendarViewDirection === 'past' && offset < 0) {
                while (monthNum < 1) {
                    monthNum = 12 + monthNum;
                    yearNum--;
                }
            }
            const { initialViewEndDate } = options;
            // const initialViewStartDate = options.initialViewStartDate; // TODO: to be used for past calendarViewDirection
            const { hideSecondMonth } = options;
            const preSelectedDateObj = options.preSelectedDate
                ? convertDateStringToDate(options.preSelectedDate)
                : null;
            const dates = [];
            const monthEndDate = new Date(yearNum, monthNum, 0);
            const monthStartDateNum =
                offset === 0 && calendarViewDirection === 'future'
                    ? this.currentWeekStartDateNum
                    : 1;
            const monthStartDate = new Date(yearNum, monthNum - 1, monthStartDateNum);
            const startDateDayIndex = monthStartDate.getDay();

            let monthClass = '';
            let isMonthThatHidesSomeDaysForInitialView;
            let monthEndDateNum = monthEndDate.getDate();

            if (
                offset === 0
                && calendarViewDirection === 'past'
                && monthEndDateNum > this.currentWeekEndDateNum
            ) {
                monthEndDateNum = this.currentWeekEndDateNum;
            }

            if (options.preSelectedDate) {
                if (
                    monthStartDate.getFullYear() === preSelectedDateObj.getFullYear()
                    && monthStartDate.getMonth() === preSelectedDateObj.getMonth()
                ) {
                    monthClass += ' month-preselected';
                } else if (monthStartDate > preSelectedDateObj) {
                    monthClass += ' month-hidden';
                }
            } else if (Math.abs(offset) === 1 && hideSecondMonth) {
                monthClass = `${monthClass} month-hidden`;
            } else if (Math.abs(offset) > 1) {
                monthClass = `${monthClass} month-hidden`;
            }

            if (
                Math.abs(offset) === options.monthsAfterToLoadOffset
                && calendarViewDirection === 'future'
            ) {
                monthClass += ' last-available-month';
            }
            if (
                Math.abs(offset) === options.monthsBeforeToLoadOffset
                && calendarViewDirection === 'past'
            ) {
                // TODO - re-check this logic if past direction
                monthClass += ' last-available-month';
            }

            // populate dates array
            for (let i = monthStartDateNum; i <= monthEndDateNum; i++) {
                let dayClasses = '';
                const dateString =
                    `${yearNum.toString()
                    }-${
                        (`0${monthNum}`).slice(-2)
                    }-${
                        (`0${i}`).slice(-2)}`;

                if (offset === 0 && i === this.todayDateNum) {
                    dayClasses += ' current-day';
                }
                if (offset === 0 && i < this.todayDateNum && calendarViewDirection === 'future') {
                    dayClasses += ' unavailable-day';
                }
                if (offset === 0 && i > this.todayDateNum && calendarViewDirection === 'past') {
                    dayClasses += ' unavailable-day';
                }
                if (convertDateStringToDate(dateString).getDay() === 0) {
                    dayClasses += ' sunday';
                }
                if (
                    this.hideSomeDaysForInitialView
                    && convertDateStringToDate(initialViewEndDate).getMonth() + 1 === monthNum
                    && convertDateStringToDate(initialViewEndDate).getDate() < i
                ) {
                    dayClasses += ' day-hidden';
                    isMonthThatHidesSomeDaysForInitialView = true;
                }
                const dateObject = {
                    dateNum: i,
                    dayClasses,
                    inputValue: dateString,
                    isSelectable:
                        this.selectableDatesData.findIndex((date) => date.date === dateString) > -1
                };
                dates.push(dateObject);
            }

            const monthToAdd = {
                monthLabel: MONTHS_OF_YEAR[monthNum - 1],
                monthIndex: monthNum,
                monthString: `${MONTHS_OF_YEAR[monthNum - 1]}-${yearNum?.toString()}`,
                yearNum,
                dates,
                startDateDayIndex,
                monthClass,
                isMonthThatHidesSomeDaysForInitialView
            };
            return monthToAdd;
        },
        async showAnotherMonth() {
            this.isLoading = true;
            let monthToShow;
            let monthStartDateNum = 0;

            if (this.hideSomeDaysForInitialView) {
                monthToShow = this.months.find(({ isMonthThatHidesSomeDaysForInitialView }) =>
                    isMonthThatHidesSomeDaysForInitialView);
                // find the first day-hidden to become the next api call start date
                monthStartDateNum =
                    monthToShow.dates.find(({ dayClasses }) => dayClasses.includes('day-hidden'))
                        .dateNum - 1;
            } else {
                if (this.calendarViewDirection === 'future') {
                    monthToShow = this.months.find((month) =>
                        month.monthClass.includes('month-hidden'));
                }
                if (this.calendarViewDirection === 'past') {
                    // TODO: UPDATE THIS WITH CORRECT PAST LOOKING LOGIC
                    monthToShow = this.months.find((month) =>
                        month.monthClass.includes('month-hidden'));
                }
            }
            if (monthToShow) {
                // make new API call with this month's start and end dates
                await this.updateSelectableDates(
                    monthToShow.dates[monthStartDateNum].inputValue,
                    monthToShow.dates[monthToShow.dates.length - 1].inputValue
                );
                this.isLoading = false;
                this.hideSomeDaysForInitialView = false; // if hid days on initial partial view, this will reveal those days
                monthToShow.monthClass = monthToShow.monthClass.replace(' month-hidden', '');
                this.scrollToElement(monthToShow.monthString);

                if (monthToShow.monthClass.includes('last-available-month')) this.disableViewMoreDatesButton = true;
            }
        },
        async updateSelectableDates(monthStart, monthEnd) {
            console.log(this.mainStore);
            const moreSelectableDates = await this.customSelectableDatesCallback(
                monthStart,
                monthEnd,
                this.mainStore.order.serviceLocation.appointmentType,
                this.mainStore.order.serviceLocation.provider.providerNumber
            );

            moreSelectableDates.days.forEach((selectableDate) => {
                const index = this.selectableDatesData.findIndex((dateObj) => dateObj.date === selectableDate.date);
                if (index === -1) this.selectableDatesData.push(selectableDate);
                this.months.forEach((month) => {
                    // TODO: avoid checking all calendar dates; maybe only ones between monthStart and monthEnd as defined above?
                    month.dates.forEach((date) => {
                        if (date.inputValue === selectableDate.date) {
                            date.isSelectable = true;
                        }
                    });
                });
            });
        },
        scrollToElement(elementId, duration = 800, easing = 'ease-in-out') {
            const wrapper = document.querySelector('.page-container-grouped-styles');
            const target = document.getElementById(elementId);
            const initY = wrapper.scrollTop;
            const wrapperRect = wrapper.getBoundingClientRect();
            const targetRect = target.getBoundingClientRect();
            const targetY = targetRect.top - wrapperRect.top - BUFFER_OFFSET;
            const timingFunc = TIMINGFUNC_MAP[easing];
            let start = null;
            const step = (timestamp) => {
                start = start || timestamp;
                const time = Math.min(1, (timestamp - start) / duration);
                const percentageNew = timingFunc(time);
                const distanceToGo = targetY;
                const thisDistance = percentageNew * distanceToGo;
                wrapper.scrollTo(0, initY + thisDistance);
                if (percentageNew < 1) {
                    window.requestAnimationFrame(step);
                }
            };
            window.requestAnimationFrame(step);
        }
    }
};
</script>

<style lang="scss" scoped>
@import "@/styles/ux-variables-svg-strings.scss";

.date-picker-hidden {
    opacity: 0;
    max-height: 0;
}
.date-picker {
    position: relative;
    flex-grow: 0;
    display: flex;
    flex-direction: column;

    fieldset {
        flex-grow: 1;
        position: relative;
    }
    .loader {
        height: 2rem;
        width: calc(100% - 1.5rem);

        &::after {
            width: 1.5rem;
            height: 1.5rem;
        }
    }
    .calendar-grid-container {
        margin: 0 auto 2rem auto;
        max-width: 414px;
        position: relative;
        transition: height ease 2s, opacity ease 2s;
        display: grid;
        grid-template-columns: repeat(7, 1fr);
        justify-content: center;
        align-items: center;
        padding: 0 0.75rem;
        opacity: 1;

        .grid-item {
            text-align: center;
            margin: 10px 3px;
            font-size: 0.875rem;
            line-height: 1.5;

            &.first-day-,
            &.first-day-0 {
                grid-column-start: 1;
            }
            &.first-day-1 {
                grid-column-start: 2;
            }
            &.first-day-2 {
                grid-column-start: 3;
            }
            &.first-day-3 {
                grid-column-start: 4;
            }
            &.first-day-4 {
                grid-column-start: 5;
            }
            &.first-day-5 {
                grid-column-start: 6;
            }
            &.first-day-6 {
                grid-column-start: 7;
            }
        }

        .separator-line {
            grid-area: 2/1/2/8;
            border-top: 1px solid $gray-500;
            margin: 0.5rem 0;
        }

        .month-year {
            grid-area: 1 / 1 / 2 / 5;
            text-transform: uppercase;
            font-weight: 300;
            letter-spacing: 0.75px;
        }
        .legend {
            grid-area: 1 / 5 / 2 / 8;
            .legend-circle {
                border-radius: 50%;
                width: 16px;
                height: 16px;
                background-color: $blue-100;
                border: 1px solid $blue;
            }
        }
        .nav-back,
        .nav-forward {
            display: none;
        }

        .radio-wrapper {
            position: relative;
            display: flex;
            justify-content: center;
            align-items: center;
            outline: none;
            height: 1.5rem;
            opacity: 1;
            transition: height ease 250ms, opacity ease 250ms;

            input[type="radio"] {
                position: absolute; //override bootstrap
                height: 0;
                opacity: 0;

                &:focus-visible + label {
                    box-shadow: 0 0 0 2.5px $blue;
                }

                &:focus + label,
                &:checked:focus + label {
                    box-shadow: 0 0 0 3px #fff, 0 0 0 5.5px #1574a1;
                    background-color: $blue;
                    color: $white;
                    &.current-day {
                        &:after {
                            background-color: $white;
                        }
                        .first-day {
                            color: $white;
                        }
                    }
                }

                &:checked + label {
                    color: $white;
                    background: $blue;
                    &:after {
                        background-color: $white;
                    }
                    .first-day {
                        color: $white;
                    }
                }
            }

            .first-day {
                position: absolute;
                font-size: 9px;
                font-weight: 500;
                color: $gray-600;
                top: 0;
                z-index: 1;
            }

            label {
                position: relative;
                cursor: pointer;
                display: flex;
                justify-content: center;
                align-items: center;
                min-width: 2.5rem;
                width: 2.5rem;
                height: 2.5rem;

                span {
                    &.small {
                        font-size: 0.75rem;
                        color: $gray-550;
                    }
                }

                &:hover,
                &:checked {
                    @include media-breakpoint-up(sm) {
                        box-shadow: 0 0 0 4px transparent;
                        background-color: $blue;
                        color: $white;
                        &:after {
                            background-color: $white;
                        }
                    }
                    cursor: pointer;
                    &.current-day {
                        + .first-day {
                            color: $white;
                        }
                    }
                    .first-day {
                        color: $white;
                    }
                }
                + p {
                    display: none;
                }
            }

            &.selectable-day {
                label {
                    color: $blue;
                    background-color: $blue-100;
                    border: 1px solid $blue;
                    min-width: 2.5rem;
                    width: 2.5rem;
                    border-radius: 50%;
                }
            }
            &.unavailable-day {
                label {
                    color: $gray-500;
                    background-color: $gray-100;
                    border: none;
                    pointer-events: none;
                }
            }
            &.unavailable-day:not(&.sunday) {
                label {
                    &::before {
                        content: "";
                        display: inline-block;
                        position: absolute;
                        left: -1rem;
                        width: 1rem;
                        height: 2.5rem;
                        background: $gray-100;
                    }
                }
            }
            &.current-day {
                label {
                    font-weight: 500;
                    color: $black;

                    &:after {
                        content: "";
                        width: 0.25rem;
                        height: 0.25rem;
                        border-radius: 50%;
                        background-color: $black;
                        position: absolute;
                        top: 28px;
                    }
                    .first-day {
                        color: $blue;
                    }
                }
            }
        }

        &.partial-month-initial-view {
            .day-hidden {
                opacity: 0;
                overflow: hidden;
                display: flex;
                margin: 0;
                max-height: 0;
            }
        }
        &.month-hidden {
            opacity: 0;
            max-height: 0;
            margin-bottom: 0;
            overflow: hidden;
        }
    }

    .btn-link {
        font-weight: 500;
        text-underline-offset: 4px;
        flex-grow: 0;
        &:focus {
            box-shadow: none;
        }
    }

    .past {
        .calendar-grid-container {
            .month-year {
                grid-area: 1 / 1 / 2 / 6;
            }
            .nav-forward {
                grid-area: 1 / 7 / 2 / 8;
                display: flex;
                justify-content: flex-end;
                button {
                    &:after {
                        content: "";
                        position: absolute;
                        width: 7px;
                        height: 12px;
                        background-image: url($svg-date-picker-forward-button);
                    }
                }
            }
            .nav-back {
                grid-area: 1 / 6 / 2 / 7;
                display: flex;
                justify-content: flex-end;
                button {
                    &:after {
                        content: "";
                        position: absolute;
                        width: 7px;
                        height: 12px;
                        background-image: url($svg-date-picker-nav-back-button);
                    }
                }
            }
            .nav-back,
            .nav-forward {
                button {
                    position: relative;
                    border-radius: 50%;
                    width: 28px;
                    height: 28px;
                    background-color: $blue-100;
                    border: 1px solid $blue;
                    display: flex;
                    justify-content: center;
                    align-items: center;
                    &:focus,
                    &:focus-visible {
                        border: 2.5px solid $blue;
                        box-shadow: none;
                        background-color: $blue-100;
                        color: $white;
                    }
                }
            }
        }
    }
}
.btn-link {
    display: block;
    position: relative;
    height: 2rem;
    width: 100%;
    justify-content: center;
    background: transparent;
    border: none;
    font-weight: 500;
    text-underline-offset: 4px;
    z-index: 2;
}

.form-test-error {
    margin: 0 auto;
    max-width: 414px;
    text-align: left;
}
</style>
