<template>
    <div class="date-picker d-flex align-items-center">
        <button
            class="date-picker__nav-btn"
            :disabled="!canGoBack"
            aria-label="Previous dates"
            @click="goBack">
            ‹
        </button>
        <div class="date-picker__track d-flex flex-grow-1">
            <button
                v-for="date in visibleDates"
                :key="date.value"
                class="date-picker__day-card d-flex flex-column align-items-center justify-content-center"
                :class="{
                    'date-picker__day-card--selected': isSelected(date.value),
                    'date-picker__day-card--disabled': !date.isAvailable,
                }"
                :disabled="!date.isAvailable"
                :aria-pressed="isSelected(date.value)"
                :aria-label="`${date.dayAbbr} ${date.monthAbbr} ${date.day}`"
                @click="selectDate(date)">
                <span class="date-picker__day-abbr">{{ date.dayAbbr }}</span>
                <span class="date-picker__day-date">{{ date.monthAbbr }} {{ date.day }}</span>
            </button>
        </div>
        <button
            class="date-picker__nav-btn"
            :disabled="!canGoForward"
            aria-label="Next dates"
            @click="goForward">
            ›
        </button>
    </div>
</template>

<script>
const DAY_ABBRS = ["SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"];
const MONTH_ABBRS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
const MOBILE_WINDOW_SIZE = 3;
const DESKTOP_WINDOW_SIZE = 5;
const DESKTOP_BREAKPOINT_PX = 768;

function toLocalDateString(date) {
    const y = date.getFullYear();
    const m = String(date.getMonth() + 1).padStart(2, "0");
    const d = String(date.getDate()).padStart(2, "0");
    return `${y}-${m}-${d}`;
}

function parseLocalDate(str) {
    const [year, month, day] = str.split("-").map(Number);
    return new Date(year, month - 1, day);
}

export default {
    name: "datePicker",
    props: {
        availableDates: {
            type: Array,
            default: () => [],
        },
        startDate: {
            type: String,
            default: null,
        },
        endDate: {
            type: String,
            default: null,
        },
        modelValue: {
            type: String,
            default: null,
        },
        isLoadingDates: {
            type: Boolean,
            default: false,
        },
    },
    emits: ["update:modelValue", "requestMoreDates"],
    data() {
        return {
            windowStart: 0,
            windowSize: DESKTOP_WINDOW_SIZE,
        };
    },
    computed: {
        allDates() {
            const availableSet = new Set(this.availableDates);

            const hasBounds = this.startDate && this.endDate;
            const hasAvailable = this.availableDates.length > 0;
            if (!hasBounds && !hasAvailable) return [];

            let first, last;
            if (hasBounds) {
                first = parseLocalDate(this.startDate);
                last = parseLocalDate(this.endDate);
            } else {
                const sorted = [...this.availableDates].sort();
                first = parseLocalDate(sorted[0]);
                last = parseLocalDate(sorted[sorted.length - 1]);
            }

            const dates = [];
            const cursor = new Date(first);
            while (cursor <= last) {
                const value = toLocalDateString(cursor);
                dates.push({
                    value,
                    isAvailable: availableSet.has(value),
                    dayAbbr: DAY_ABBRS[cursor.getDay()],
                    monthAbbr: MONTH_ABBRS[cursor.getMonth()],
                    day: cursor.getDate(),
                });
                cursor.setDate(cursor.getDate() + 1);
            }
            return dates;
        },
        visibleDates() {
            return this.allDates.slice(this.windowStart, this.windowStart + this.windowSize);
        },
        canGoBack() {
            return this.windowStart > 0;
        },
        canGoForward() {
            return !this.isLoadingDates && this.allDates.length > 0;
        },
    },
    watch: {
        // Only reset position when startDate changes — that signals a fresh range.
        // Extending endDate/availableDates (loading more) keeps the current window.
        startDate() {
            this.windowStart = 0;
        },
    },
    mounted() {
        this.updateWindowSize();
        window.addEventListener("resize", this.updateWindowSize);
        if (this.modelValue && this.allDates.length) {
            const idx = this.allDates.findIndex((d) => d.value === this.modelValue);
            if (idx !== -1) {
                this.windowStart = Math.floor(idx / this.windowSize) * this.windowSize;
            }
        }
    },
    beforeUnmount() {
        window.removeEventListener("resize", this.updateWindowSize);
    },
    methods: {
        updateWindowSize() {
            this.windowSize =
                window.innerWidth >= DESKTOP_BREAKPOINT_PX
                    ? DESKTOP_WINDOW_SIZE
                    : MOBILE_WINDOW_SIZE;
        },
        goBack() {
            this.windowStart = Math.max(0, this.windowStart - this.windowSize);
        },
        goForward() {
            if (this.isLoadingDates) return;
            const isAtEnd = this.windowStart + this.windowSize >= this.allDates.length;
            if (isAtEnd) {
                this.$emit("requestMoreDates");
            } else {
                const maxStart = Math.max(0, this.allDates.length - this.windowSize);
                this.windowStart = Math.min(maxStart, this.windowStart + this.windowSize);
            }
        },
        selectDate(date) {
            if (!date.isAvailable) return;
            this.$emit("update:modelValue", date.value);
        },
        isSelected(value) {
            return this.modelValue === value;
        },
    },
};
</script>

<style lang="scss">
.date-picker {
    gap: 0.25rem;

    &__nav-btn {
        flex-shrink: 0;
        width: 2rem;
        height: 2rem;
        border: none;
        background: transparent;
        font-size: 2rem;
        line-height: 1;
        color: $blue;
        cursor: pointer;
        display: flex;
        align-items: center;
        justify-content: center;
        padding: 0;
        border-radius: 50%;
        transition: background 150ms ease;

        &:hover:not(:disabled) {
            background: $blue-100;
        }

        &:disabled {
            color: $gray-300;
            cursor: default;
        }
    }

    &__track {
        gap: 0.5rem;
    }

    &__day-card {
        flex: 1;
        min-width: 0;
        border: 1px solid $gray-200;
        border-radius: $border-radius-lg;
        background: $white;
        padding: 0.625rem 0.25rem;
        cursor: pointer;
        transition:
            background 150ms ease,
            border-color 150ms ease;

        &:hover:not(:disabled):not(.date-picker__day-card--selected) {
            border-color: $blue;
        }

        &--selected {
            background: $blue;
            border-color: $blue;

            .date-picker__day-abbr,
            .date-picker__day-date {
                color: $white;
            }
        }

        &--disabled {
            background: $gray-100;
            border-color: $gray-200;
            cursor: default;

            .date-picker__day-abbr,
            .date-picker__day-date {
                color: $gray-300;
            }
        }
    }

    &__day-abbr {
        font-family: $font-family-sans-serif-semibold;
        font-size: $font-size-12;
        color: $gray-600;
        text-transform: uppercase;
        line-height: 1.2;
    }

    &__day-date {
        font-family: $font-family-sans-serif-bold;
        font-size: $font-size-14;
        color: $gray-700;
        line-height: 1.4;
        white-space: nowrap;
    }
}
</style>
