import { jsxs, jsx } from 'react/jsx-runtime';
import { ChevronLeftIcon, ChevronRightIcon } from '@heroicons/react/24/outline';
import { useReducedMotion, motion, AnimatePresence } from 'motion/react';
import React__default, { useMemo, useState, useRef, useEffect, useCallback } from 'react';
import { cn } from '../../../../utils/cn.js';
import { isCurrentMonth, isDateDisabled, isSameDay } from '../calendar.utils.js';
import { monthTransitionVariants, dateRowTransitionVariants } from './CalendarMini.animations.js';
import { calendarMiniTheme } from './CalendarMini.theme.js';
import { Button } from '../../Button/Button.js';

/**
 * Generate array of months centered around current month
 */
const generateMonths = (centerMonth, count) => {
    const months = [];
    const halfCount = Math.floor(count / 2);
    for (let i = -halfCount; i <= halfCount; i++) {
        const date = new Date(centerMonth);
        date.setMonth(date.getMonth() + i);
        months.push(date);
    }
    return months;
};
const CalendarMini = React__default.forwardRef(({ selectedDate, currentMonth, onDateSelect, onMonthChange, visibleMonths = 5, visibleDates = 7, minDate, maxDate, disabledDates, startFrom = "today", shouldAnimate = true, showTodayButton = true, className, theme, ...rest }, ref) => {
    const shouldReduceMotion = useReducedMotion();
    const enableAnimations = shouldAnimate && !shouldReduceMotion;
    const today = useMemo(() => new Date(), []);
    // Default to today's date if not provided
    const defaultSelectedDate = selectedDate !== undefined ? selectedDate : today;
    // Initialize startDate based on currentMonth and startFrom props
    const [startDate, setStartDate] = useState(() => {
        const initial = currentMonth || new Date();
        if (startFrom === "today" && isCurrentMonth(initial, new Date())) {
            return new Date(); // Start from today
        }
        return new Date(initial.getFullYear(), initial.getMonth(), 1); // Start from month beginning
    });
    const [direction, setDirection] = useState(0);
    const monthScrollRef = useRef(null);
    // Guard visibleMonths to ensure it's an odd number
    const normalizedVisibleMonths = useMemo(() => {
        if (visibleMonths % 2 === 0) {
            if (process.env.NODE_ENV !== "production") {
                console.warn(`[CalendarMini]: visibleMonths should be an odd number. Received ${visibleMonths}, using ${visibleMonths + 1} instead.`);
            }
            return visibleMonths + 1;
        }
        return visibleMonths;
    }, [visibleMonths]);
    // Sync startDate when currentMonth prop changes externally
    useEffect(() => {
        if (currentMonth) {
            const newMonth = new Date(currentMonth);
            if (startFrom === "today" && isCurrentMonth(newMonth, new Date())) {
                setStartDate(new Date()); // Start from today
            }
            else {
                setStartDate(new Date(newMonth.getFullYear(), newMonth.getMonth(), 1));
            }
        }
    }, [currentMonth, startFrom]);
    // Auto-scroll to selectedDate if it's outside visible range
    useEffect(() => {
        if (defaultSelectedDate && defaultSelectedDate instanceof Date) {
            const selectedYear = defaultSelectedDate.getFullYear();
            const selectedMonth = defaultSelectedDate.getMonth();
            // Check if selected date is within visible date range
            const firstVisibleDate = dates[0];
            const lastVisibleDate = dates[dates.length - 1];
            if (firstVisibleDate && lastVisibleDate) {
                const isBeforeRange = defaultSelectedDate < firstVisibleDate;
                const isAfterRange = defaultSelectedDate > lastVisibleDate;
                if (isBeforeRange || isAfterRange) {
                    // Jump to the selected date's month
                    const newStartDate = new Date(selectedYear, selectedMonth, defaultSelectedDate.getDate());
                    setStartDate(newStartDate);
                    setDirection(isAfterRange ? 1 : -1);
                }
            }
        }
    }, [defaultSelectedDate]); // Only watch defaultSelectedDate, not dates to avoid loops
    // Generate dates sequentially from startDate
    const dates = useMemo(() => {
        const result = [];
        const current = new Date(startDate);
        for (let i = 0; i < visibleDates; i++) {
            result.push(new Date(current));
            current.setDate(current.getDate() + 1);
        }
        return result;
    }, [startDate, visibleDates]);
    // Derive activeMonth from the middle date of visible range
    const activeMonth = useMemo(() => {
        const middleIndex = Math.floor(dates.length / 2);
        const middleDate = dates[middleIndex] || new Date();
        return new Date(middleDate.getFullYear(), middleDate.getMonth(), 1);
    }, [dates]);
    // Generate months centered around activeMonth
    const months = useMemo(() => generateMonths(activeMonth, normalizedVisibleMonths), [activeMonth, normalizedVisibleMonths]);
    // Navigation handlers - slide by visibleDates count
    const handlePrevMonth = useCallback(() => {
        setDirection(-1);
        setStartDate((prev) => {
            const newDate = new Date(prev);
            newDate.setDate(newDate.getDate() - visibleDates);
            // Calculate which month the new dates will be in
            const newMonth = new Date(newDate.getFullYear(), newDate.getMonth(), 1);
            onMonthChange === null || onMonthChange === void 0 ? void 0 : onMonthChange(newMonth);
            return newDate;
        });
    }, [visibleDates, onMonthChange]);
    const handleNextMonth = useCallback(() => {
        setDirection(1);
        setStartDate((prev) => {
            const newDate = new Date(prev);
            newDate.setDate(newDate.getDate() + visibleDates);
            // Calculate which month the new dates will be in
            const newMonth = new Date(newDate.getFullYear(), newDate.getMonth(), 1);
            onMonthChange === null || onMonthChange === void 0 ? void 0 : onMonthChange(newMonth);
            return newDate;
        });
    }, [visibleDates, onMonthChange]);
    const handleMonthClick = useCallback((month) => {
        const clickedMonth = new Date(month);
        setDirection(clickedMonth > activeMonth ? 1 : -1);
        // Set startDate to the beginning of the clicked month
        const newStartDate = new Date(month.getFullYear(), month.getMonth(), 1);
        setStartDate(newStartDate);
        onMonthChange === null || onMonthChange === void 0 ? void 0 : onMonthChange(month);
    }, [activeMonth, onMonthChange]);
    const handleDateClick = useCallback((date) => {
        if (!isDateDisabled(date, minDate, maxDate, disabledDates) &&
            onDateSelect) {
            onDateSelect(date);
        }
    }, [minDate, maxDate, disabledDates, onDateSelect]);
    const handleTodayClick = useCallback(() => {
        const todayDate = new Date();
        setDirection(todayDate > startDate ? 1 : -1);
        setStartDate(todayDate);
        const todayMonth = new Date(todayDate.getFullYear(), todayDate.getMonth(), 1);
        onMonthChange === null || onMonthChange === void 0 ? void 0 : onMonthChange(todayMonth);
        onDateSelect === null || onDateSelect === void 0 ? void 0 : onDateSelect(todayDate);
    }, [startDate, onMonthChange, onDateSelect]);
    // Check if today is in the visible date range
    const isTodayVisible = useMemo(() => {
        const todayDate = new Date();
        return dates.some((date) => isSameDay(date, todayDate));
    }, [dates]);
    // Keyboard navigation
    const handleKeyDown = useCallback((event, action) => {
        if (event.key === "Enter" || event.key === " ") {
            event.preventDefault();
            action();
        }
    }, []);
    // Scroll to center active month
    useEffect(() => {
        if (monthScrollRef.current) {
            const container = monthScrollRef.current;
            const activeIndex = Math.floor(normalizedVisibleMonths / 2);
            const scrollLeft = activeIndex * (container.scrollWidth / normalizedVisibleMonths);
            container.scrollLeft = scrollLeft;
        }
    }, [normalizedVisibleMonths]);
    // Format month abbreviation
    const formatMonth = (date) => {
        return date.toLocaleDateString("en-US", { month: "short" });
    };
    // Format day name
    const formatDayName = (date) => {
        return date.toLocaleDateString("en-US", { weekday: "short" });
    };
    // Format date number
    const formatDateNumber = (date) => {
        return date.getDate().toString().padStart(2, "0");
    };
    // Check if month is active
    const isMonthActive = useCallback((month) => {
        return (month.getFullYear() === activeMonth.getFullYear() &&
            month.getMonth() === activeMonth.getMonth());
    }, [activeMonth]);
    // Check if date is selected
    const isDateSelected = useCallback((date) => {
        return defaultSelectedDate ? isSameDay(date, defaultSelectedDate) : false;
    }, [defaultSelectedDate]);
    // Check if date is today
    const isDateToday = useCallback((date) => {
        return isSameDay(date, today);
    }, [today]);
    // Merge theme
    const mergedTheme = {
        ...calendarMiniTheme,
        ...theme,
    };
    const MonthRow = enableAnimations ? motion.div : "div";
    const DateItem = enableAnimations ? motion.button : "button";
    return (jsxs("div", { ref: ref, className: cn(mergedTheme.baseStyle, className), role: "region", "aria-label": "Mini calendar", ...rest, children: [jsx(Button, { iconOnly: true, color: "neutral", variant: "soft", className: "!flex-shrink !flex-grow-0 !w-fit self-stretch !h-auto !min-h-0 px-0.5", onClick: handlePrevMonth, "aria-label": "Previous month", children: jsx(ChevronLeftIcon, { className: "size-5 text-[var(--color-text-primary)]" }) }), jsxs("div", { className: "flex flex-col gap-1 relative", children: [jsxs("div", { className: "flex items-center gap-1", children: [jsx("div", { className: "flex flex-col relative overflow-hidden flex-1", style: {
                                    maskImage: "linear-gradient(to right, transparent, black 16px, black calc(100% - 16px), transparent)",
                                    WebkitMaskImage: "linear-gradient(to right, transparent, black 16px, black calc(100% - 16px), transparent)",
                                }, children: jsx("div", { ref: monthScrollRef, className: cn(mergedTheme.monthRowStyle), role: "tablist", "aria-label": "Month selection", children: jsx(AnimatePresence, { mode: "popLayout", initial: false, custom: direction, children: jsx(MonthRow, { custom: direction, ...(enableAnimations && {
                                                variants: monthTransitionVariants,
                                                initial: "enter",
                                                animate: "center",
                                                exit: "exit",
                                                transition: { duration: 0.3 },
                                            }), className: "flex gap-4", children: months.map((month, index) => {
                                                const isActive = isMonthActive(month);
                                                return (jsx("button", { onClick: () => handleMonthClick(month), onKeyDown: (e) => handleKeyDown(e, () => handleMonthClick(month)), "data-state": isActive ? "active" : undefined, className: cn(mergedTheme.monthItemStyle, !isActive && "opacity-60"), role: "tab", "aria-selected": isActive, "aria-label": `${formatMonth(month)} ${month.getFullYear()}`, type: "button", children: formatMonth(month) }, `${month.getFullYear()}-${month.getMonth()}`));
                                            }) }, `${activeMonth.getFullYear()}-${activeMonth.getMonth()}`) }) }) }), showTodayButton && !isTodayVisible && (jsx(Button, { size: "sm", variant: "link", onClick: handleTodayClick, "aria-label": "Jump to today", className: "mr-7", children: "Today" }))] }), jsx("div", { className: "relative overflow-hidden", style: {
                            maskImage: "linear-gradient(to right, transparent, black 16px, black calc(100% - 16px), transparent)",
                            WebkitMaskImage: "linear-gradient(to right, transparent, black 16px, black calc(100% - 16px), transparent)",
                        }, children: jsx("div", { className: cn(mergedTheme.dateRowStyle), role: "list", "aria-label": "Date selection", children: jsx(AnimatePresence, { mode: "popLayout", initial: false, custom: direction, children: jsx(motion.div, { custom: direction, ...(enableAnimations && {
                                        variants: dateRowTransitionVariants,
                                        initial: "enter",
                                        animate: "center",
                                        exit: "exit",
                                        transition: {
                                            type: "spring",
                                            stiffness: 350,
                                            damping: 30,
                                            mass: 0.6,
                                        },
                                    }), role: "presentation", className: "flex gap-1", children: dates.map((date, index) => {
                                        const isSelected = isDateSelected(date);
                                        const isToday = isDateToday(date);
                                        const isNextMonth = !isCurrentMonth(date, activeMonth);
                                        const disabled = isDateDisabled(date, minDate, maxDate, disabledDates);
                                        // Determine state for data attribute
                                        let state;
                                        if (isSelected) {
                                            state = "selected";
                                        }
                                        else if (isToday) {
                                            state = "today";
                                        }
                                        return (jsxs(DateItem, { onClick: () => !disabled && handleDateClick(date), onKeyDown: (e) => !disabled &&
                                                handleKeyDown(e, () => handleDateClick(date)), disabled: disabled, "data-state": state, "data-disabled": disabled ? "" : undefined, className: cn(mergedTheme.dateItemStyle, isNextMonth && "opacity-60"), role: "listitem", "aria-label": date.toLocaleDateString("en-US", {
                                                weekday: "long",
                                                year: "numeric",
                                                month: "long",
                                                day: "numeric",
                                            }), "aria-selected": isSelected, "aria-current": isToday ? "date" : undefined, "aria-disabled": disabled, type: "button", ...(enableAnimations && {
                                                whileTap: !disabled ? { scale: 0.95 } : undefined,
                                            }), children: [jsx("div", { className: "text-base font-medium opacity-60", children: formatDayName(date) }), jsx("time", { dateTime: date.toISOString(), className: cn("font-semibold"), children: formatDateNumber(date) })] }, date.toISOString()));
                                    }) }, `${startDate.getTime()}-dates`) }) }) })] }), jsx(Button, { iconOnly: true, color: "neutral", variant: "soft", className: "!flex-shrink !flex-grow-0 !w-fit self-stretch !h-auto !min-h-0 px-0.5", onClick: handleNextMonth, "aria-label": "Next month", children: jsx(ChevronRightIcon, { className: "size-5 text-[var(--color-text-primary)]" }) })] }));
});
CalendarMini.displayName = "CalendarMini";

export { CalendarMini };
