"use client";

import {
	addMonths,
	addWeeks,
	format,
	isValid,
	parse,
	parseISO,
	startOfDay,
} from "date-fns";
import { CalendarIcon } from "lucide-react";
import * as React from "react";
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 { cn } from "@/lib/utils";

interface DateTimePickerProps {
	value: string;
	onChange: (value: string) => void;
	allDay: boolean;
	placeholder?: string;
	className?: string;
}

type QuickShortcut = "Today" | "Next week" | "Next month";

interface QuickShortcutResult {
	keepOpen: true;
	nextMonth: Date;
	nextValue: string;
}

function getInputValue(value: string, allDay: boolean): string {
	const parsed = parseValue(value);
	if (!parsed) return "";

	return allDay
		? format(parsed, "yyyy-MM-dd")
		: format(parsed, "yyyy-MM-dd'T'HH:mm");
}

/** Parse the incoming ISO / date string into a Date object, or return undefined. */
function parseValue(value: string): Date | undefined {
	if (!value) return undefined;
	// Try ISO 8601 with offset (e.g. "2024-01-15T14:30:00+00:00")
	const iso = parseISO(value);
	if (isValid(iso)) return iso;
	// Try plain date "YYYY-MM-DD"
	const plain = parse(value, "yyyy-MM-dd", new Date());
	if (isValid(plain)) return plain;
	// Try datetime-local "YYYY-MM-DDTHH:mm"
	const local = parse(value, "yyyy-MM-dd'T'HH:mm", new Date());
	if (isValid(local)) return local;
	return undefined;
}

/** Emit ISO date string from Date + time parts depending on allDay mode. */
function buildValue(
	date: Date,
	hour: number,
	minute: number,
	allDay: boolean,
): string {
	if (allDay) {
		return format(date, "yyyy-MM-dd");
	}
	const hh = String(hour).padStart(2, "0");
	const mm = String(minute).padStart(2, "0");
	return `${format(date, "yyyy-MM-dd")}T${hh}:${mm}:00`;
}

function resolveQuickShortcutDate(shortcut: QuickShortcut, now: Date): Date {
	const today = startOfDay(now);

	if (shortcut === "Today") return today;
	if (shortcut === "Next week") return startOfDay(addWeeks(today, 1));

	return startOfDay(addMonths(today, 1));
}

function getTimeParts(value: string, allDay: boolean) {
	const parsed = parseValue(value);

	if (!parsed || allDay) {
		return { hour: 0, minute: 0 };
	}

	return {
		hour: parsed.getHours(),
		minute: parsed.getMinutes(),
	};
}

export function getCalendarMonthForValue(
	value: string,
	fallbackDate: Date,
): Date {
	return parseValue(value) ?? fallbackDate;
}

export function applyQuickDateShortcut({
	shortcut,
	value,
	allDay,
	now,
}: {
	shortcut: QuickShortcut;
	value: string;
	allDay: boolean;
	now: Date;
}): QuickShortcutResult {
	const nextMonth = resolveQuickShortcutDate(shortcut, now);
	const { hour, minute } = getTimeParts(value, allDay);

	return {
		keepOpen: true,
		nextMonth,
		nextValue: buildValue(nextMonth, hour, minute, allDay),
	};
}

export function DateTimePicker({
	value,
	onChange,
	allDay,
	placeholder = "Pick a date",
	className,
}: DateTimePickerProps) {
	const parsed = parseValue(value);
	const { hour: currentHour, minute: currentMinute } = getTimeParts(
		value,
		allDay,
	);
	const [open, setOpen] = React.useState(false);
	const [visibleMonth, setVisibleMonth] = React.useState(() =>
		getCalendarMonthForValue(value, new Date()),
	);

	React.useEffect(() => {
		setVisibleMonth(getCalendarMonthForValue(value, new Date()));
	}, [value]);

	const handleDaySelect = (day: Date | undefined) => {
		if (!day) return;
		onChange(buildValue(day, currentHour, currentMinute, allDay));
		setVisibleMonth(day);
		setOpen(false);
	};

	const handleQuickSelect = (shortcut: QuickShortcut) => {
		const result = applyQuickDateShortcut({
			shortcut,
			value,
			allDay,
			now: new Date(),
		});

		onChange(result.nextValue);
		setVisibleMonth(result.nextMonth);
		setOpen(result.keepOpen);
	};

	const quickOptions: QuickShortcut[] = ["Today", "Next week", "Next month"];

	const displayLabel = parsed
		? allDay
			? format(parsed, "MMM d, yyyy")
			: format(parsed, "MMM d, yyyy · HH:mm")
		: null;

	return (
		<div className={cn("w-full", className)}>
			<div className="flex items-center gap-2">
				<Input
					type={allDay ? "date" : "datetime-local"}
					value={getInputValue(value, allDay)}
					onChange={(event) => {
						onChange(event.target.value);
					}}
					placeholder={placeholder}
					className="flex-1"
				/>
				<Popover open={open} onOpenChange={setOpen}>
					<PopoverTrigger asChild>
						<Button
							type="button"
							variant="outline"
							size="icon"
							className={cn(!displayLabel && "text-muted-foreground")}
							aria-label={displayLabel ?? placeholder}
						>
							<CalendarIcon className="h-3.5 w-3.5 shrink-0 text-muted-foreground/70" />
						</Button>
					</PopoverTrigger>
					<PopoverContent
						className="w-[min(22rem,calc(100vw-2rem))] p-0"
						align="start"
						sideOffset={8}
					>
						<div className="flex flex-wrap gap-1 border-b border-border px-3 py-2">
							{quickOptions.map((label) => (
								<Button
									key={label}
									type="button"
									variant="ghost"
									size="sm"
									onClick={() => handleQuickSelect(label)}
									className="h-auto px-2 py-1 text-xs text-muted-foreground"
								>
									{label}
								</Button>
							))}
						</div>
						<Calendar
							mode="single"
							month={visibleMonth}
							onMonthChange={setVisibleMonth}
							selected={parsed}
							onSelect={handleDaySelect}
							initialFocus
						/>
					</PopoverContent>
				</Popover>
			</div>
		</div>
	);
}
