"use client";

import { addDays, format, isValid, parse } from "date-fns";
import { CalendarIcon, ChevronDownIcon } from "lucide-react";
import * as React from "react";
import type { DropdownProps, Matcher } from "react-day-picker";
import { Button } from "@/components/ui/button";
import { Calendar } from "@/components/ui/calendar";
import {
	Combobox,
	ComboboxContent,
	ComboboxEmpty,
	ComboboxInput,
	ComboboxItem,
	ComboboxList,
} from "@/components/ui/combobox";
import { Field, FieldLabel } from "@/components/ui/field";
import {
	Popover,
	PopoverContent,
	PopoverTrigger,
} from "@/components/ui/popover";
import { useIsMobile } from "@/hooks/use-mobile";

interface DropdownItem {
	disabled?: boolean;
	label: string;
	value: string;
}

function CalendarDropdown(props: DropdownProps) {
	const isMobile = useIsMobile();
	const { options, value, onChange, "aria-label": ariaLabel } = props;

	const items: DropdownItem[] =
		options?.map((option) => ({
			disabled: option.disabled,
			label: option.label,
			value: option.value.toString(),
		})) ?? [];

	const selectedItem = items.find((item) => item.value === value?.toString());

	const handleValueChange = (newValue: DropdownItem | null) => {
		if (onChange && newValue) {
			const syntheticEvent = {
				target: { value: newValue.value },
			} as React.ChangeEvent<HTMLSelectElement>;
			onChange(syntheticEvent);
		}
	};

	return (
		<>
			{isMobile ? (
				<div className="relative flex items-center">
					<select
						aria-label={ariaLabel}
						className="absolute inset-0 z-10 w-full cursor-pointer opacity-0"
						value={value?.toString() ?? ""}
						onChange={onChange}
					>
						{options?.map((option) => (
							<option
								key={option.value}
								value={option.value}
								disabled={option.disabled}
							>
								{option.label}
							</option>
						))}
					</select>
					<Button
						variant="ghost"
						size="sm"
						className="pointer-events-none h-8 w-full justify-between gap-2 px-2 font-medium"
						tabIndex={-1}
					>
						{selectedItem?.label}
						<ChevronDownIcon className="size-4 opacity-50" />
					</Button>
				</div>
			) : (
				<Combobox
					aria-label={ariaLabel}
					autoHighlight
					items={items}
					onValueChange={handleValueChange}
					value={selectedItem}
				>
					<ComboboxInput
						className="mx-1 h-8 min-w-[90px] border-none bg-transparent shadow-none outline-none ring-0 focus-within:ring-0 before:hidden hover:bg-accent hover:text-accent-foreground focus-within:bg-accent focus-within:text-accent-foreground **:[input]:w-0 **:[input]:flex-1 **:[input]:cursor-pointer **:[input]:text-center **:[input]:font-medium"
						onFocus={(e) => e.currentTarget.select()}
					/>
					<ComboboxContent aria-label={ariaLabel}>
						<ComboboxEmpty>No items found.</ComboboxEmpty>
						<ComboboxList>
							{(item: DropdownItem) => (
								<ComboboxItem
									disabled={item.disabled}
									key={item.value}
									value={item}
								>
									{item.label}
								</ComboboxItem>
							)}
						</ComboboxList>
					</ComboboxContent>
				</Combobox>
			)}
		</>
	);
}

export interface DatePickerProps {
	date?: Date;
	onSelect?: (date: Date | undefined) => void;
	startMonth?: Date;
	endMonth?: Date;
	disabled?: Matcher | Matcher[];
	label?: string;
	id?: string;
	variant?: "button" | "input";
	open?: boolean;
	onOpenChange?: (open: boolean) => void;
	month?: Date;
	onMonthChange?: (month: Date) => void;
}

export function DatePicker({
	date,
	onSelect,
	startMonth = new Date(1900, 0, 1),
	endMonth = new Date(2100, 11, 31),
	disabled,
	label,
	id: providedId,
	variant = "button",
	open: controlledOpen,
	onOpenChange: controlledOnOpenChange,
	month: controlledMonth,
	onMonthChange: controlledOnMonthChange,
}: DatePickerProps) {
	const isMobile = useIsMobile();
	const fallbackId = React.useId();
	const id = providedId ?? fallbackId;

	const [uncontrolledOpen, setUncontrolledOpen] = React.useState(false);
	const open = controlledOpen ?? uncontrolledOpen;
	const setOpen = controlledOnOpenChange ?? setUncontrolledOpen;

	const today = new Date();

	const [uncontrolledMonth, setUncontrolledMonth] = React.useState(
		date || today,
	);
	const month = controlledMonth ?? uncontrolledMonth;
	const setMonth = controlledOnMonthChange ?? setUncontrolledMonth;

	const [inputValue, setInputValue] = React.useState(() =>
		date ? format(date, "yyyy-MM-dd") : "",
	);

	React.useEffect(() => {
		setInputValue(date ? format(date, "yyyy-MM-dd") : "");
	}, [date]);

	const handleSelect = (selectedDate: Date | undefined) => {
		onSelect?.(selectedDate);
		setOpen(false);
	};

	const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
		const nextValue = event.target.value;
		const numericValue = nextValue.replace(/\D/g, "");

		let formattedValue = "";
		if (numericValue.length > 0) {
			formattedValue += numericValue.substring(0, 4);
		}
		if (numericValue.length >= 5) {
			formattedValue += `-${numericValue.substring(4, 6)}`;
		}
		if (numericValue.length >= 7) {
			formattedValue += `-${numericValue.substring(6, 8)}`;
		}

		setInputValue(formattedValue);

		if (!formattedValue) {
			onSelect?.(undefined);
			return;
		}

		if (formattedValue.length === 10) {
			const nextDate = parse(formattedValue, "yyyy-MM-dd", new Date());
			if (isValid(nextDate)) {
				onSelect?.(nextDate);
				setMonth(nextDate);
			}
		}
	};

	const triggerContent =
		variant === "input" ? (
			<div className="flex h-10 w-full cursor-text items-center gap-0.5 rounded-md border border-input bg-background px-3 py-2 shadow-xs outline-none transition-shadow has-[input:focus]:border-ring has-[input:focus]:ring-[3px] has-[input:focus]:ring-ring/50">
				<input
					id={id}
					type="text"
					inputMode="text"
					placeholder="YYYY-MM-DD"
					value={inputValue}
					onChange={handleInputChange}
					onClick={(event) => event.stopPropagation()}
					className="inline-flex h-full w-full min-w-0 border-0 bg-transparent text-sm tabular-nums font-mono outline-none transition-colors focus:bg-transparent disabled:cursor-not-allowed disabled:opacity-50"
				/>
				<PopoverTrigger asChild>
					<Button
						type="button"
						variant="ghost"
						size="icon"
						className="ml-auto size-7 shrink-0 text-muted-foreground hover:text-foreground"
					>
						<CalendarIcon aria-hidden="true" className="size-4" />
					</Button>
				</PopoverTrigger>
			</div>
		) : (
			<PopoverTrigger asChild>
				<Button
					id={id}
					className="w-full justify-start font-normal"
					variant="outline"
				>
					<CalendarIcon aria-hidden="true" className="mr-2 h-4 w-4" />
					{date ? format(date, "PPP") : <span>Pick a date</span>}
				</Button>
			</PopoverTrigger>
		);

	const popover = (
		<Popover open={open} onOpenChange={setOpen}>
			{triggerContent}
			<PopoverContent className="w-auto p-0" align="start">
				<div className={isMobile ? "flex flex-col" : "flex"}>
					<div
						className={
							isMobile
								? "relative order-1 border-t py-1 ps-1"
								: "relative py-1 ps-1"
						}
					>
						<div
							className={
								isMobile
									? "flex h-full flex-col"
									: "flex h-full flex-col border-e pe-3"
							}
						>
							<Button
								className="w-full justify-start"
								onClick={() => {
									handleSelect(today);
									setMonth(today);
								}}
								size="sm"
								variant="ghost"
							>
								Today
							</Button>
							<Button
								className="w-full justify-start"
								onClick={() => {
									const tomorrow = addDays(today, 1);
									handleSelect(tomorrow);
									setMonth(tomorrow);
								}}
								size="sm"
								variant="ghost"
							>
								Tomorrow
							</Button>
							<Button
								className="w-full justify-start"
								onClick={() => {
									const in3Days = addDays(today, 3);
									handleSelect(in3Days);
									setMonth(in3Days);
								}}
								size="sm"
								variant="ghost"
							>
								In 3 days
							</Button>
							<Button
								className="w-full justify-start"
								onClick={() => {
									const inAWeek = addDays(today, 7);
									handleSelect(inAWeek);
									setMonth(inAWeek);
								}}
								size="sm"
								variant="ghost"
							>
								In a week
							</Button>
						</div>
					</div>
					<Calendar
						className={isMobile ? "pb-3" : "ps-2"}
						mode="single"
						captionLayout="dropdown"
						components={{ Dropdown: CalendarDropdown }}
						startMonth={startMonth}
						endMonth={endMonth}
						disabled={disabled}
						month={month}
						onMonthChange={setMonth}
						onSelect={handleSelect}
						selected={date}
					/>
				</div>
			</PopoverContent>
		</Popover>
	);

	if (label) {
		return (
			<Field>
				<FieldLabel htmlFor={id}>{label}</FieldLabel>
				{popover}
			</Field>
		);
	}

	return popover;
}
