import { Button } from '@/Components/ui/button';
import { Calendar } from '@/Components/ui/calendar';
import {
    Popover,
    PopoverContent,
    PopoverTrigger,
} from '@/Components/ui/popover';
import { ToggleGroup, ToggleGroupItem } from '@/Components/ui/toggle-group';
import { it } from 'date-fns/locale';
import dayjs, { Dayjs } from 'dayjs';
import { CalendarDays, ChevronLeft, ChevronRight, X } from 'lucide-react';
import { useEffect, useState } from 'react';
import { DateRange } from 'react-day-picker';

export interface PeriodRange {
    from: Dayjs;
    to: Dayjs;
}

interface DayNavigatorProps {
    date: Dayjs;
    onChange: (date: Dayjs) => void;
    /** Days (YYYY-MM-DD, ascending) with at least one measure: enabled in the calendar, arrows jump between them. */
    availableDates?: string[];
    /** Active period; set only while a period is selected. */
    range?: PeriodRange | null;
    /** Enables the period mode: called when the user picks a from–to range. */
    onRangeChange?: (from: Dayjs, to: Dayjs) => void;
}

/** True while the viewport is at the Tailwind `sm` breakpoint or narrower. */
function useIsMobile(query = '(max-width: 639px)'): boolean {
    const [isMobile, setIsMobile] = useState(
        () => typeof window !== 'undefined' && window.matchMedia(query).matches,
    );

    useEffect(() => {
        const mql = window.matchMedia(query);
        const onChange = () => setIsMobile(mql.matches);
        mql.addEventListener('change', onChange);
        setIsMobile(mql.matches);
        return () => mql.removeEventListener('change', onChange);
    }, [query]);

    return isMobile;
}

export default function DayNavigator({
    date,
    onChange,
    availableDates,
    range,
    onRangeChange,
}: DayNavigatorProps) {
    const isMobile = useIsMobile();
    const [open, setOpen] = useState(false);
    const [mode, setMode] = useState<'day' | 'period'>(
        range ? 'period' : 'day',
    );
    const [pendingRange, setPendingRange] = useState<DateRange | undefined>();

    const dateString = date.format('YYYY-MM-DD');
    const availableSet = availableDates && new Set(availableDates);

    const previousDate = availableDates
        ? [...availableDates].reverse().find((day) => day < dateString)
        : undefined;
    const nextDate = availableDates
        ? availableDates.find((day) => day > dateString)
        : undefined;

    const onPreviousClick = () => {
        if (availableDates) {
            if (previousDate) {
                onChange(dayjs(previousDate));
            }
            return;
        }
        onChange(date.subtract(1, 'days'));
    };

    const onNextClick = () => {
        if (availableDates) {
            if (nextDate) {
                onChange(dayjs(nextDate));
            }
            return;
        }
        onChange(date.add(1, 'days'));
    };

    const isDayDisabled = (day: Date) => {
        if (!availableSet) {
            return false;
        }
        return !availableSet.has(dayjs(day).format('YYYY-MM-DD'));
    };

    const onDaySelect = (day: Date | undefined) => {
        if (day) {
            onChange(dayjs(day));
            setOpen(false);
        }
    };

    const onPeriodSelect = (selected: DateRange | undefined) => {
        setPendingRange(selected);
        if (selected?.from && selected?.to && onRangeChange) {
            onRangeChange(dayjs(selected.from), dayjs(selected.to));
            setOpen(false);
            setPendingRange(undefined);
        }
    };

    // Clearing the period navigates back to the day view: onChange sends only the
    // `date` param, which drops the from/to query and restores single-day mode.
    const onResetPeriod = () => {
        setOpen(false);
        setMode('day');
        setPendingRange(undefined);
        onChange(date);
    };

    const onOpenChange = (isOpen: boolean) => {
        setOpen(isOpen);
        if (isOpen) {
            setMode(range ? 'period' : 'day');
            setPendingRange(undefined);
        }
    };

    const label = range
        ? `${range.from.format('DD/MM/YYYY')} – ${range.to.format('DD/MM/YYYY')}`
        : date.format('DD/MM/YYYY');

    const arrowsDisabled = Boolean(range);
    const periodMonths = isMobile ? 1 : 2;
    const periodDefaultMonth = (range ? range.from : date)
        .subtract(isMobile ? 0 : 1, 'month')
        .toDate();

    return (
        <div className="flex flex-wrap items-center justify-center gap-2">
            {!arrowsDisabled && (
                <Button
                    variant="outline"
                    className="h-8 w-8 rounded-full border-0 bg-white p-0 shadow-md print:hidden"
                    onClick={onPreviousClick}
                    disabled={availableDates ? !previousDate : false}
                >
                    <span className="sr-only">Go to previous day</span>
                    <ChevronLeft />
                </Button>
            )}
            <Popover open={open} onOpenChange={onOpenChange}>
                <PopoverTrigger asChild>
                    <Button
                        variant="outline"
                        className="h-8 max-w-full gap-2 rounded-full border-0 bg-white px-3 text-sm font-medium shadow-md print:hidden"
                    >
                        <CalendarDays className="h-4 w-4 shrink-0" />
                        <span className="truncate">{label}</span>
                    </Button>
                </PopoverTrigger>
                <PopoverContent
                    className="w-auto max-w-[calc(100vw-1rem)] p-0"
                    align="center"
                    collisionPadding={8}
                >
                    {onRangeChange && (
                        <div className="flex justify-center border-b p-2">
                            <ToggleGroup
                                type="single"
                                size="sm"
                                value={mode}
                                onValueChange={(value) => {
                                    if (value) {
                                        setMode(value as 'day' | 'period');
                                        setPendingRange(undefined);
                                    }
                                }}
                            >
                                <ToggleGroupItem value="day">
                                    Giorno
                                </ToggleGroupItem>
                                <ToggleGroupItem value="period">
                                    Periodo
                                </ToggleGroupItem>
                            </ToggleGroup>
                        </div>
                    )}
                    {mode === 'day' ? (
                        <Calendar
                            mode="single"
                            locale={it}
                            captionLayout="dropdown-buttons"
                            fromYear={2000}
                            toDate={new Date()}
                            defaultMonth={date.toDate()}
                            selected={date.toDate()}
                            disabled={isDayDisabled}
                            onSelect={onDaySelect}
                            initialFocus
                        />
                    ) : (
                        <div className="max-w-full overflow-x-auto">
                            <Calendar
                                mode="range"
                                locale={it}
                                numberOfMonths={periodMonths}
                                toDate={new Date()}
                                defaultMonth={periodDefaultMonth}
                                selected={
                                    pendingRange ??
                                    (range
                                        ? {
                                              from: range.from.toDate(),
                                              to: range.to.toDate(),
                                          }
                                        : undefined)
                                }
                                disabled={isDayDisabled}
                                onSelect={onPeriodSelect}
                                initialFocus
                            />
                            <div className="flex items-center justify-between gap-2 border-t p-2">
                                <p className="text-muted-foreground text-xs">
                                    Seleziona il primo e l&apos;ultimo giorno
                                </p>
                                {range && (
                                    <Button
                                        variant="ghost"
                                        size="sm"
                                        className="h-7 shrink-0 gap-1 px-2 text-xs"
                                        onClick={onResetPeriod}
                                    >
                                        <X className="h-3.5 w-3.5" />
                                        Reset
                                    </Button>
                                )}
                            </div>
                        </div>
                    )}
                </PopoverContent>
            </Popover>
            {arrowsDisabled && (
                <Button
                    variant="outline"
                    className="h-8 w-8 rounded-full border-0 bg-white p-0 shadow-md print:hidden"
                    onClick={onResetPeriod}
                    title="Rimuovi il periodo"
                >
                    <span className="sr-only">Reset period</span>
                    <X className="h-4 w-4" />
                </Button>
            )}
            {!arrowsDisabled && (
                <Button
                    variant="outline"
                    className="h-8 w-8 rounded-full border-0 bg-white p-0 shadow-md print:hidden"
                    onClick={onNextClick}
                    disabled={availableDates ? !nextDate : false}
                >
                    <span className="sr-only">Go to next day</span>
                    <ChevronRight />
                </Button>
            )}
        </div>
    );
}
