"use client";

import * as React from "react";
import { Calendar as CalendarIcon, X } from "lucide-react";

import { cn } from "@/lib/utils";

import { Calendar } from "@/components/ui/calendar";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
	Popover,
	PopoverContent,
	PopoverTrigger,
} from "@/components/ui/popover";

import { isValidIsoDateYmd } from "@/lib/frontend/search/dateRange";
import { getSearchDateRangeValidation } from "@/lib/frontend/search/searchDateValidation";
import { buildDatePresets } from "@/lib/frontend/search/datePresets";

function pad2(n) {
	return String(n).padStart(2, "0");
}

function dateToIsoYmd(date) {
	if (!(date instanceof Date) || Number.isNaN(date.getTime())) return null;

	const y = date.getFullYear();
	const m = pad2(date.getMonth() + 1);
	const d = pad2(date.getDate());
	return `${y}-${m}-${d}`;
}

function isoYmdToDate(iso) {
	if (typeof iso !== "string") return null;
	if (!isValidIsoDateYmd(iso)) return null;

	const [y, m, d] = iso.split("-").map((x) => Number(x));
	return new Date(y, m - 1, d);
}

const deDateFormatter = new Intl.DateTimeFormat("de-DE", {
	day: "2-digit",
	month: "2-digit",
	year: "numeric",
});

function formatIsoToDe(iso) {
	const d = isoYmdToDate(iso);
	return d ? deDateFormatter.format(d) : "";
}

function getSummaryLabel(from, to) {
	if (from && to) return `${formatIsoToDe(from)} – ${formatIsoToDe(to)}`;
	if (from) return `ab ${formatIsoToDe(from)}`;
	if (to) return `bis ${formatIsoToDe(to)}`;
	return "Zeitraum auswählen";
}

export default function SearchDateRangePicker({
	from,
	to,
	onDateRangeChange,
	isSubmitting,
	className,
}) {
	const disabled = Boolean(isSubmitting);

	const [open, setOpen] = React.useState(false);
	const [activeField, setActiveField] = React.useState("from"); // "from" | "to"

	const fromRef = React.useRef(null);
	const toRef = React.useRef(null);

	const fromDate = isoYmdToDate(from);
	const toDate = isoYmdToDate(to);

	const validation = getSearchDateRangeValidation(from ?? null, to ?? null);
	const isRangeInvalid = validation?.code === "VALIDATION_SEARCH_RANGE";

	const now = React.useMemo(() => new Date(), []);
	const presets = React.useMemo(() => buildDatePresets({ now }), [now]);

	// Split into two rows (4 + 3):
	// Row 1: short ranges (today/yesterday/last 7/last 30)
	// Row 2: larger ranges (this month/last month/this year)
	const presetsRow1 = presets.slice(0, 4);
	const presetsRow2 = presets.slice(4);

	const [month, setMonth] = React.useState(() => {
		return fromDate || toDate || new Date();
	});

	React.useEffect(() => {
		if (!open) return;

		if (from && !to) {
			setActiveField("to");
			requestAnimationFrame(() => toRef.current?.focus?.());
		} else {
			setActiveField("from");
			requestAnimationFrame(() => fromRef.current?.focus?.());
		}

		setMonth(fromDate || toDate || new Date());
		// eslint-disable-next-line react-hooks/exhaustive-deps
	}, [open]);

	function safeOnDateRangeChange(next) {
		if (typeof onDateRangeChange !== "function") return;

		const hasFrom = Object.prototype.hasOwnProperty.call(next || {}, "from");
		const hasTo = Object.prototype.hasOwnProperty.call(next || {}, "to");

		onDateRangeChange({
			from: hasFrom ? next.from : from ?? null,
			to: hasTo ? next.to : to ?? null,
		});
	}

	let calendarSelected = undefined;
	let invalidInterval = null;

	if (fromDate && toDate) {
		if (isRangeInvalid) {
			const min = fromDate < toDate ? fromDate : toDate;
			const max = fromDate < toDate ? toDate : fromDate;
			calendarSelected = { from: min, to: max };
			invalidInterval = { from: min, to: max };
		} else {
			calendarSelected = { from: fromDate, to: toDate };
		}
	} else if (fromDate) {
		calendarSelected = { from: fromDate, to: undefined };
	} else if (toDate) {
		calendarSelected = { from: toDate, to: toDate };
	}

	const calendarModifiers =
		isRangeInvalid && invalidInterval
			? {
					invalid_range: invalidInterval,
					invalid_range_edge: [fromDate, toDate].filter(Boolean),
			  }
			: undefined;

	const calendarModifiersClassNames =
		isRangeInvalid && invalidInterval
			? {
					invalid_range:
						"bg-destructive/10 text-destructive dark:bg-destructive/20 dark:text-destructive",
					invalid_range_edge:
						"!bg-destructive !text-white hover:!bg-destructive/90",
			  }
			: undefined;

	function focusActiveField(nextField) {
		if (nextField === "from") {
			requestAnimationFrame(() => fromRef.current?.focus?.());
		} else {
			requestAnimationFrame(() => toRef.current?.focus?.());
		}
	}

	function handlePickDay(...args) {
		if (disabled) return;

		let day = args[0];
		let modifiers = args[1];

		if (!(day instanceof Date) && args[1] instanceof Date) {
			day = args[1];
			modifiers = args[2];
		}

		if (!(day instanceof Date) || Number.isNaN(day.getTime())) return;
		if (modifiers?.disabled) return;

		const iso = dateToIsoYmd(day);
		if (!iso) return;

		if (activeField === "from") {
			safeOnDateRangeChange({ from: iso });
			setActiveField("to");
			focusActiveField("to");
			return;
		}

		safeOnDateRangeChange({ to: iso });
		setActiveField("to");
		focusActiveField("to");
	}

	function handleClearFrom(e) {
		e?.preventDefault?.();
		e?.stopPropagation?.();
		if (disabled) return;

		safeOnDateRangeChange({ from: null });
		setActiveField("from");
		focusActiveField("from");
	}

	function handleClearTo(e) {
		e?.preventDefault?.();
		e?.stopPropagation?.();
		if (disabled) return;

		safeOnDateRangeChange({ to: null });
		setActiveField("to");
		focusActiveField("to");
	}

	function handleReset() {
		if (disabled) return;

		safeOnDateRangeChange({ from: null, to: null });
		setActiveField("from");
		setMonth(new Date());
		focusActiveField("from");
	}

	function applyPreset(preset) {
		if (disabled) return;
		if (!preset?.from || !preset?.to) return;

		safeOnDateRangeChange({ from: preset.from, to: preset.to });

		const nextMonth =
			isoYmdToDate(preset.from) || isoYmdToDate(preset.to) || new Date();
		setMonth(nextMonth);

		setActiveField("to");
		focusActiveField("to");
	}

	const summary = getSummaryLabel(from, to);

	const activeInputClass =
		"border-blue-600 bg-blue-50 dark:border-blue-900 dark:bg-blue-950";

	const calendarKey = `${from || ""}|${to || ""}|${
		isRangeInvalid ? "inv" : "ok"
	}`;

	return (
		<div className={cn("grid gap-2", className)}>
			<Label>Zeitraum</Label>

			<Popover open={open} onOpenChange={setOpen}>
				<PopoverTrigger asChild>
					<Button
						type="button"
						variant="outline"
						disabled={disabled}
						className={cn(
							"w-[240px] justify-between font-normal",
							!from && !to ? "text-muted-foreground" : ""
						)}
						title="Zeitraum auswählen"
					>
						<span className="truncate">{summary}</span>
						<CalendarIcon className="ml-2 h-4 w-4 opacity-70" />
					</Button>
				</PopoverTrigger>

				{/* Fit to content (2 months). DayPicker supports multiple months via numberOfMonths. */}
				<PopoverContent align="start" className="w-fit p-0">
					<div className="w-fit space-y-4 p-4">
						<div className="grid grid-cols-2 gap-4">
							<div className="space-y-1">
								<Label>Von</Label>
								<div className="relative">
									<Input
										ref={fromRef}
										readOnly
										disabled={disabled}
										value={from ? formatIsoToDe(from) : ""}
										placeholder="TT.MM.JJJJ"
										className={cn(
											"pr-8",
											activeField === "from" ? activeInputClass : ""
										)}
										onFocus={() => setActiveField("from")}
										onClick={() => setActiveField("from")}
									/>
									{from ? (
										<button
											type="button"
											className="absolute right-2 top-1/2 -translate-y-1/2 rounded-sm p-1 opacity-70 hover:opacity-100"
											onClick={handleClearFrom}
											aria-label="Startdatum löschen"
											title="Startdatum löschen"
										>
											<X className="h-4 w-4" />
										</button>
									) : null}
								</div>
							</div>

							<div className="space-y-1">
								<Label>Bis</Label>
								<div className="relative">
									<Input
										ref={toRef}
										readOnly
										disabled={disabled}
										value={to ? formatIsoToDe(to) : ""}
										placeholder="TT.MM.JJJJ"
										className={cn(
											"pr-8",
											activeField === "to" ? activeInputClass : ""
										)}
										onFocus={() => setActiveField("to")}
										onClick={() => setActiveField("to")}
									/>
									{to ? (
										<button
											type="button"
											className="absolute right-2 top-1/2 -translate-y-1/2 rounded-sm p-1 opacity-70 hover:opacity-100"
											onClick={handleClearTo}
											aria-label="Enddatum löschen"
											title="Enddatum löschen"
										>
											<X className="h-4 w-4" />
										</button>
									) : null}
								</div>
							</div>
						</div>

						<Calendar
							key={calendarKey}
							mode="range"
							numberOfMonths={2}
							captionLayout="dropdown"
							month={month}
							onMonthChange={setMonth}
							selected={calendarSelected}
							modifiers={calendarModifiers}
							modifiersClassNames={calendarModifiersClassNames}
							onDayClick={handlePickDay}
						/>

						{/* Presets: two flex rows (no grid), always looks balanced */}
						<div className="space-y-2">
							<div className="text-sm text-muted-foreground">Schnellwahl</div>

							<div className="flex flex-wrap gap-2">
								{presetsRow1.map((p) => (
									<Badge
										key={p.key}
										asChild
										className={[
											"bg-white text-black border-border",
											"hover:bg-white/90",
											"dark:bg-white dark:text-black",
										].join(" ")}
									>
										<button
											type="button"
											className="cursor-pointer select-none disabled:opacity-60"
											disabled={disabled}
											onClick={() => applyPreset(p)}
											title={p.label}
										>
											{p.label}
										</button>
									</Badge>
								))}
							</div>

							<div className="flex flex-wrap gap-2">
								{presetsRow2.map((p) => (
									<Badge key={p.key} asChild>
										<button
											type="button"
											className="cursor-pointer select-none disabled:opacity-60"
											disabled={disabled}
											onClick={() => applyPreset(p)}
											title={p.label}
										>
											{p.label}
										</button>
									</Badge>
								))}
							</div>
						</div>

						<div className="flex justify-end pt-1">
							<Button
								type="button"
								variant="outline"
								disabled={disabled}
								onClick={handleReset}
							>
								Zurücksetzen
							</Button>
						</div>
						<p className="text-xs text-muted-foreground text-center">
							Tipp: Für einen einzelnen Tag setzen Sie <b>Von</b> und <b>Bis</b>{" "}
							auf dasselbe Datum.
						</p>
					</div>
				</PopoverContent>
			</Popover>
		</div>
	);
}
