import * as React from "react";
import {
    format,
    parseISO,
    subDays,
    subMonths,
    startOfMonth,
    endOfMonth,
    differenceInCalendarDays,
    isAfter,
    isBefore,
} from "date-fns";
import { ptBR } from "date-fns/locale";
import { AlertTriangle, CalendarIcon } from "lucide-react";

import { cn } from "@/lib/utils";
import { Button } from "@/Components/ui/button";
import { Calendar } from "@/Components/ui/calendar";
import { Input } from "@/Components/ui/input";
import {
    Popover,
    PopoverContent,
    PopoverTrigger,
} from "@/Components/ui/popover";
import { useIsMobile } from "@/hooks/use-mobile";
import { sameSelection } from "@/context/dashboardPresets";

function toDate(iso) {
    return iso ? parseISO(iso + "T12:00:00") : undefined;
}

function toIso(date) {
    return format(date, "yyyy-MM-dd");
}

function formatShort(iso) {
    return format(parseISO(iso + "T12:00:00"), "dd/MM/yyyy");
}

// Lista visivel no painel lateral. `selection` aponta para um preset do
// registry compartilhado (resources/js/context/dashboardPresets.js). A label
// pode ser custom para a UI; a semantica e a do registry.
const VISIBLE_PRESETS = [
    { label: "Esta semana",      selection: { id: "this_week" } },
    { label: "7 dias atrás",     selection: { id: "last_n_days", params: { n: 7 } } },
    { label: "Semana passada",   selection: { id: "last_week" } },
    { label: "14 dias atrás",    selection: { id: "last_n_days", params: { n: 14 } } },
    { label: "Este mês",         selection: { id: "this_month" } },
    { label: "30 dias atrás",    selection: { id: "last_n_days", params: { n: 30 } } },
    { label: "Último mês",       selection: { id: "last_month" } },
];

export function DateRangePicker({
    value,
    onChange,
    onSelectPreset,
    selection: activeSelection = null,
    minDate,
    maxDate,
    maxRangeDays,
    className,
}) {
    const isMobile = useIsMobile();
    const yesterday = React.useMemo(() => subDays(new Date(), 1), []);
    // maxBound = limite superior selecionavel. Default = ontem (D-1).
    // Integracoes em tempo real (ex.: Exent Hub) passam maxDate=hoje (D-0).
    const maxBound = React.useMemo(
        () => (maxDate ? toDate(maxDate) : yesterday),
        [maxDate, yesterday],
    );
    const minDateObj = minDate ? toDate(minDate) : undefined;

    const [open, setOpen] = React.useState(false);
    const [draft, setDraft] = React.useState({
        from: toDate(value.startDate),
        to: toDate(value.endDate),
    });
    const [viewMonth, setViewMonth] = React.useState(() =>
        startOfMonth(subMonths(toDate(value.endDate) ?? yesterday, isMobile ? 0 : 1))
    );
    const [customDays, setCustomDays] = React.useState("");

    React.useEffect(() => {
        if (open) {
            setDraft({
                from: toDate(value.startDate),
                to: toDate(value.endDate),
            });
            setViewMonth(
                startOfMonth(subMonths(toDate(value.endDate) ?? maxBound, isMobile ? 0 : 1))
            );
            setCustomDays("");
        }
    }, [open, value.startDate, value.endDate, maxBound, isMobile]);

    function applyCustomRange(from, to) {
        let start = from;
        if (minDateObj && isBefore(start, minDateObj)) start = minDateObj;
        if (maxRangeDays) {
            const span = differenceInCalendarDays(to, start) + 1;
            if (span > maxRangeDays) start = subDays(to, maxRangeDays - 1);
        }
        onChange({ startDate: toIso(start), endDate: toIso(to) });
        setOpen(false);
    }

    function handlePreset(preset) {
        if (onSelectPreset) {
            onSelectPreset(preset.selection);
            setOpen(false);
            return;
        }
        // Fallback (sem callback de preset): resolve localmente como custom.
        const today = new Date();
        if (preset.selection.id === "last_n_days") {
            applyCustomRange(subDays(maxBound, preset.selection.params.n - 1), maxBound);
        } else if (preset.selection.id === "last_month") {
            const lm = subMonths(today, 1);
            applyCustomRange(startOfMonth(lm), endOfMonth(lm));
        } else {
            // demais presets dependem de maxBound; sem callback de preset,
            // calculamos com base no maxBound.
            applyCustomRange(maxBound, maxBound);
        }
    }

    function handleApply() {
        if (!draft.from) return;
        const from = draft.from;
        const to = draft.to ?? draft.from;
        applyCustomRange(from, to);
    }

    function handleCancel() {
        setDraft({
            from: toDate(value.startDate),
            to: toDate(value.endDate),
        });
        setOpen(false);
    }

    function handleCustomDaysApply() {
        let n = parseInt(customDays, 10);
        if (!Number.isFinite(n) || n < 1) return;
        if (maxRangeDays && n > maxRangeDays) {
            n = maxRangeDays;
            setCustomDays(String(n));
        }
        if (onSelectPreset) {
            onSelectPreset({ id: "last_n_days", params: { n } });
            setOpen(false);
        } else {
            applyCustomRange(subDays(maxBound, n - 1), maxBound);
        }
    }

    function handleCustomDaysChange(e) {
        const digitsOnly = e.target.value.replace(/\D/g, "");
        setCustomDays(digitsOnly);
    }

    // Spans para feedback visual quando ha cap de dias.
    const draftSpan =
        draft.from && draft.to
            ? differenceInCalendarDays(draft.to, draft.from) + 1
            : null;
    const draftExceedsCap = !!(
        maxRangeDays && draftSpan && draftSpan > maxRangeDays
    );
    const customDaysExceedsCap = !!(
        maxRangeDays &&
        customDays &&
        parseInt(customDays, 10) > maxRangeDays
    );

    const disabledMatcher = [{ after: maxBound }];
    if (minDateObj) disabledMatcher.push({ before: minDateObj });

    const triggerLabel =
        value.startDate && value.endDate
            ? `${formatShort(value.startDate)} - ${formatShort(value.endDate)}`
            : "Selecione o período";

    return (
        <Popover open={open} onOpenChange={setOpen}>
            <PopoverTrigger asChild>
                <Button
                    variant="outline"
                    className={cn(
                        "justify-start text-left font-normal gap-2",
                        className
                    )}
                >
                    <CalendarIcon className="h-3.5 w-3.5" />
                    <span className="text-xs sm:text-sm">{triggerLabel}</span>
                </Button>
            </PopoverTrigger>
            <PopoverContent
                className={cn(
                    "p-0",
                    isMobile ? "w-screen max-w-none rounded-none border-x-0" : "w-auto"
                )}
                align={isMobile ? "center" : "end"}
                collisionPadding={isMobile ? 0 : undefined}
            >
                <div className="flex flex-col sm:flex-row">
                    <div className="p-3 border-b sm:border-b-0 sm:border-r sm:min-w-[11rem]">
                        {/* Presets: rolagem horizontal no mobile, coluna no desktop */}
                        <div className="flex gap-1 overflow-x-auto -mx-1 px-1 pb-1 sm:flex-col sm:overflow-visible sm:mx-0 sm:px-0 sm:pb-0">
                            {VISIBLE_PRESETS.map((preset) => {
                                const isActive = sameSelection(activeSelection, preset.selection);
                                return (
                                    <Button
                                        key={preset.label}
                                        variant={isActive ? "secondary" : "ghost"}
                                        size="sm"
                                        className="justify-start h-8 text-xs sm:text-sm shrink-0 whitespace-nowrap sm:w-full sm:shrink"
                                        onClick={() => handlePreset(preset)}
                                    >
                                        {preset.label}
                                    </Button>
                                );
                            })}
                        </div>
                        <div className="flex flex-col gap-1 pt-2 mt-2 border-t sm:mt-1 w-full">
                            <div className="flex items-center gap-2">
                                <Input
                                    type="text"
                                    inputMode="numeric"
                                    pattern="[0-9]*"
                                    placeholder="N"
                                    value={customDays}
                                    onChange={handleCustomDaysChange}
                                    onBlur={handleCustomDaysApply}
                                    onKeyDown={(e) => {
                                        if (e.key === "Enter") {
                                            e.preventDefault();
                                            handleCustomDaysApply();
                                        }
                                    }}
                                    aria-invalid={customDaysExceedsCap || undefined}
                                    className={cn(
                                        "h-8 w-14 text-xs text-center",
                                        customDaysExceedsCap && "border-amber-500 focus-visible:ring-amber-500/40",
                                    )}
                                />
                                <span className="text-xs text-muted-foreground">
                                    dias até ontem
                                    {maxRangeDays ? ` (máx. ${maxRangeDays})` : ""}
                                </span>
                            </div>
                            {customDaysExceedsCap && (
                                <p className="text-[11px] text-amber-600 dark:text-amber-500">
                                    Será ajustado para {maxRangeDays} ao aplicar.
                                </p>
                            )}
                        </div>
                    </div>

                    <div className="flex flex-col">
                        <Calendar
                            mode="range"
                            selected={draft}
                            onSelect={(range, triggerDate) => {
                                if (draft.from && draft.to && triggerDate) {
                                    setDraft({ from: triggerDate, to: undefined });
                                    return;
                                }
                                setDraft(range ?? { from: undefined, to: undefined });
                            }}
                            numberOfMonths={isMobile ? 1 : 2}
                            month={viewMonth}
                            onMonthChange={setViewMonth}
                            locale={ptBR}
                            disabled={disabledMatcher}
                            className="p-3 mx-auto [--cell-size:2.5rem] sm:mx-0 sm:[--cell-size:2rem]"
                            components={{
                                MonthCaption: ({ calendarMonth, ...rest }) => {
                                    const monthDate = calendarMonth.date;
                                    const label = format(monthDate, "LLLL 'de' yyyy", { locale: ptBR });
                                    const capitalized = label.charAt(0).toUpperCase() + label.slice(1);
                                    const handleSelectMonth = () => {
                                        let from = startOfMonth(monthDate);
                                        let to = endOfMonth(monthDate);
                                        if (minDateObj && isBefore(from, minDateObj)) from = minDateObj;
                                        if (isAfter(to, maxBound)) to = maxBound;
                                        if (isAfter(from, maxBound) || isBefore(to, from)) return;
                                        setDraft({ from, to });
                                    };
                                    return (
                                        <div {...rest} className="relative z-10 flex h-[--cell-size] w-full items-center justify-center px-[--cell-size] pointer-events-none">
                                            <button
                                                type="button"
                                                onClick={handleSelectMonth}
                                                className="pointer-events-auto select-none rounded-md px-2 py-1 text-sm font-medium hover:bg-accent hover:text-accent-foreground transition-colors cursor-pointer"
                                                title="Selecionar mês inteiro"
                                            >
                                                {capitalized}
                                            </button>
                                        </div>
                                    );
                                },
                            }}
                        />
                        {(maxRangeDays || draftExceedsCap) && (
                            <div className={cn(
                                "flex items-center gap-1.5 px-3 pt-2 text-[11px] border-t",
                                draftExceedsCap
                                    ? "text-amber-600 dark:text-amber-500"
                                    : "text-muted-foreground",
                            )}>
                                {draftExceedsCap ? (
                                    <>
                                        <AlertTriangle className="h-3 w-3 shrink-0" />
                                        <span>
                                            Selecionado: {draftSpan} dias - será limitado a {maxRangeDays} ao aplicar.
                                        </span>
                                    </>
                                ) : (
                                    <span>Máximo de {maxRangeDays} dias selecionáveis nesta aba.</span>
                                )}
                            </div>
                        )}
                        <div className="flex items-center justify-end gap-2 px-3 pb-3 pt-2 border-t">
                            <Button
                                variant="outline"
                                size="sm"
                                className="h-8 text-xs"
                                onClick={handleCancel}
                            >
                                Cancelar
                            </Button>
                            <Button
                                size="sm"
                                className="h-8 text-xs"
                                onClick={handleApply}
                                disabled={!draft.from}
                            >
                                Aplicar
                            </Button>
                        </div>
                    </div>
                </div>
            </PopoverContent>
        </Popover>
    );
}
