"use client";

import { useEffect, useState } from "react";
import { DayFlag, DayPicker, SelectionState, UI, type ClassNames } from "react-day-picker";
import { Calendar, ChevronLeft, ChevronRight, Clock } from "lucide-react";
import { cn } from "@/lib/utils";

interface DateTimePickerProps {
  value: string; // ISO string or ""
  onChange: (iso: string) => void;
  error?: boolean;
}

const QUICK_TIMES = [
  { label: "9:00 AM",  h: 9,  m: 0 },
  { label: "10:00 AM", h: 10, m: 0 },
  { label: "12:00 PM", h: 12, m: 0 },
  { label: "2:00 PM",  h: 14, m: 0 },
  { label: "4:00 PM",  h: 16, m: 0 },
  { label: "6:00 PM",  h: 18, m: 0 },
];

const MONTHS = [
  "January", "February", "March", "April", "May", "June",
  "July", "August", "September", "October", "November", "December",
];

function pad(n: number) { return String(n).padStart(2, "0"); }

function parseDate(value: string) {
  if (!value) return undefined;
  const date = new Date(value);
  return Number.isNaN(date.getTime()) ? undefined : date;
}

function toLocalISO(date: Date): string {
  return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}T${pad(date.getHours())}:${pad(date.getMinutes())}`;
}

function toDisplayHour(hour24: number) {
  return hour24 > 12 ? hour24 - 12 : hour24 === 0 ? 12 : hour24;
}

function mergeDateAndTime(date: Date, hour: string, minute: string, ampm: "AM" | "PM") {
  let h = parseInt(hour, 10);
  const m = parseInt(minute, 10);
  if (ampm === "PM" && h < 12) h += 12;
  if (ampm === "AM" && h === 12) h = 0;
  return new Date(date.getFullYear(), date.getMonth(), date.getDate(), h, m, 0);
}

function roundToNextQuarter(date: Date) {
  const rounded = new Date(date);
  rounded.setSeconds(0, 0);
  rounded.setMinutes(Math.ceil((rounded.getMinutes() + 1) / 15) * 15);
  return rounded;
}

const calendarClassNames: Partial<ClassNames> = {
  [UI.Root]: "w-full",
  [UI.Months]: "flex w-full justify-center",
  [UI.Month]: "w-full",
  [UI.MonthCaption]: "hidden",
  [UI.Nav]: "hidden",
  [UI.MonthGrid]: "w-full table-fixed border-collapse px-3",
  [UI.Weekdays]: "border-0",
  [UI.Weekday]: "py-2 text-center text-[10px] font-semibold uppercase text-gray-400 dark:text-gray-500",
  [UI.Week]: "border-0",
  [UI.Day]: "p-0 text-center align-middle",
  [UI.DayButton]: "mx-auto flex h-8 w-8 items-center justify-center rounded-lg text-sm text-gray-700 transition-colors hover:bg-gray-100 focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-1 dark:text-gray-300 dark:hover:bg-gray-800",
  [SelectionState.selected]: "font-semibold [&_.rdp-day_button]:bg-blue-600 [&_.rdp-day_button]:text-white [&_.rdp-day_button]:shadow-sm",
  [DayFlag.today]: "[&_.rdp-day_button]:border [&_.rdp-day_button]:border-blue-400 [&_.rdp-day_button]:font-semibold [&_.rdp-day_button]:text-blue-600 dark:[&_.rdp-day_button]:border-blue-500 dark:[&_.rdp-day_button]:text-blue-400",
  [DayFlag.disabled]: "opacity-35 [&_.rdp-day_button]:cursor-not-allowed [&_.rdp-day_button]:hover:bg-transparent",
  [DayFlag.outside]: "opacity-35",
};

export function DateTimePicker({ value, onChange, error }: DateTimePickerProps) {
  const now = new Date();
  const parsed = parseDate(value);
  const defaultTime = parsed ?? roundToNextQuarter(now);

  const [selectedDate, setSelectedDate] = useState<Date | undefined>(parsed);
  const [displayMonth, setDisplayMonth] = useState(new Date((parsed ?? now).getFullYear(), (parsed ?? now).getMonth()));
  const [hour, setHour] = useState(pad(toDisplayHour(defaultTime.getHours())));
  const [minute, setMinute] = useState(pad(defaultTime.getMinutes()));
  const [ampm, setAmpm] = useState<"AM" | "PM">(defaultTime.getHours() >= 12 ? "PM" : "AM");

  const startMonth = new Date(now.getFullYear(), now.getMonth());
  const endMonth = new Date(now.getFullYear() + 2, 11);
  const years = Array.from({ length: endMonth.getFullYear() - startMonth.getFullYear() + 1 }, (_, index) => startMonth.getFullYear() + index);

  useEffect(() => {
    const nextDate = parseDate(value);
    setSelectedDate(nextDate);
    if (!nextDate) return;
    setDisplayMonth(new Date(nextDate.getFullYear(), nextDate.getMonth()));
    setHour(pad(toDisplayHour(nextDate.getHours())));
    setMinute(pad(nextDate.getMinutes()));
    setAmpm(nextDate.getHours() >= 12 ? "PM" : "AM");
  }, [value]);

  const commit = (date = selectedDate, h = hour, m = minute, period = ampm) => {
    if (!date) return;
    onChange(toLocalISO(mergeDateAndTime(date, h, m, period)));
  };

  const applyQuickTime = (h: number, m: number) => {
    const displayH = toDisplayHour(h);
    const nextAmpm = h >= 12 ? "PM" : "AM";
    setHour(pad(displayH));
    setMinute(pad(m));
    setAmpm(nextAmpm);
    commit(selectedDate, pad(displayH), pad(m), nextAmpm);
  };

  const handleHourInput = (v: string) => {
    const n = parseInt(v, 10);
    if (isNaN(n)) return;
    const next = pad(Math.min(12, Math.max(1, n)));
    setHour(next);
    commit(selectedDate, next, minute, ampm);
  };

  const handleMinuteInput = (v: string) => {
    const n = parseInt(v, 10);
    if (isNaN(n)) return;
    const next = pad(Math.min(59, Math.max(0, n)));
    setMinute(next);
    commit(selectedDate, hour, next, ampm);
  };

  const handlePeriodChange = (period: "AM" | "PM") => {
    setAmpm(period);
    commit(selectedDate, hour, minute, period);
  };

  const handleSelectDate = (date: Date | undefined) => {
    if (!date) return;
    setSelectedDate(date);
    commit(date);
  };

  const changeDisplayMonth = (year: number, month: number) => {
    const nextMonth = new Date(year, month);
    if (nextMonth < startMonth || nextMonth > endMonth) return;
    setDisplayMonth(nextMonth);
  };

  const isPastQuickTime = (h: number, m: number) => {
    if (!selectedDate) return false;
    return mergeDateAndTime(selectedDate, pad(toDisplayHour(h)), pad(m), h >= 12 ? "PM" : "AM") <= now;
  };

  const canGoPrevious = displayMonth > startMonth;
  const canGoNext = displayMonth < endMonth;

  return (
    <div className={cn(
      "rounded-xl border bg-white dark:bg-gray-900 overflow-hidden shadow-sm",
      error ? "border-red-400" : "border-gray-200 dark:border-gray-700"
    )}>

      <div className="flex items-center justify-between border-b border-gray-100 px-4 py-3 dark:border-gray-800">
        <button
          type="button"
          onClick={() => changeDisplayMonth(displayMonth.getFullYear(), displayMonth.getMonth() - 1)}
          disabled={!canGoPrevious}
          className="flex h-8 w-8 items-center justify-center rounded-lg text-gray-500 transition-colors hover:bg-gray-100 hover:text-gray-900 disabled:opacity-35 dark:text-gray-400 dark:hover:bg-gray-800 dark:hover:text-gray-100"
          aria-label="Previous month"
        >
          <ChevronLeft className="h-4 w-4" />
        </button>

        <div className="flex items-center gap-2">
          <select
            value={displayMonth.getMonth()}
            onChange={(event) => changeDisplayMonth(displayMonth.getFullYear(), Number(event.target.value))}
            className="h-9 rounded-lg border border-gray-200 bg-white px-3 text-sm font-semibold text-gray-900 shadow-sm outline-none transition-colors focus:border-blue-500 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-100"
            aria-label="Select month"
          >
            {MONTHS.map((month, index) => (
              <option
                key={month}
                value={index}
                disabled={displayMonth.getFullYear() === startMonth.getFullYear() && index < startMonth.getMonth()}
              >
                {month}
              </option>
            ))}
          </select>

          <select
            value={displayMonth.getFullYear()}
            onChange={(event) => changeDisplayMonth(Number(event.target.value), displayMonth.getMonth())}
            className="h-9 rounded-lg border border-gray-200 bg-white px-3 text-sm font-semibold text-gray-900 shadow-sm outline-none transition-colors focus:border-blue-500 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-100"
            aria-label="Select year"
          >
            {years.map((year) => (
              <option key={year} value={year}>{year}</option>
            ))}
          </select>
        </div>

        <button
          type="button"
          onClick={() => changeDisplayMonth(displayMonth.getFullYear(), displayMonth.getMonth() + 1)}
          disabled={!canGoNext}
          className="flex h-8 w-8 items-center justify-center rounded-lg text-gray-500 transition-colors hover:bg-gray-100 hover:text-gray-900 disabled:opacity-35 dark:text-gray-400 dark:hover:bg-gray-800 dark:hover:text-gray-100"
          aria-label="Next month"
        >
          <ChevronRight className="h-4 w-4" />
        </button>
      </div>

      <div className="px-3 py-3">
        <DayPicker
          mode="single"
          selected={selectedDate}
          onSelect={handleSelectDate}
          disabled={{ before: new Date(now.getFullYear(), now.getMonth(), now.getDate()) }}
          month={displayMonth}
          onMonthChange={setDisplayMonth}
          startMonth={startMonth}
          endMonth={endMonth}
          hideNavigation
          fixedWeeks
          showOutsideDays
          classNames={calendarClassNames}
        />
      </div>

      {/* ── Time section ── */}
      <div className="border-t border-gray-100 dark:border-gray-800 px-4 py-3 space-y-3">

        {/* Quick time chips */}
        <div className="flex flex-wrap gap-1.5">
          {QUICK_TIMES.map((qt) => {
            const displayH = toDisplayHour(qt.h);
            const past = isPastQuickTime(qt.h, qt.m);
            const isActive =
              parseInt(hour, 10) === displayH &&
              parseInt(minute, 10) === qt.m &&
              ampm === (qt.h >= 12 ? "PM" : "AM");

            return (
              <button
                key={qt.label}
                type="button"
                onClick={() => applyQuickTime(qt.h, qt.m)}
                disabled={past}
                className={cn(
                  "rounded-full px-2.5 py-1 text-xs font-medium transition-colors",
                  isActive
                    ? "bg-blue-600 text-white"
                    : past
                    ? "bg-gray-50 text-gray-300 dark:bg-gray-800/60 dark:text-gray-600"
                    : "bg-gray-100 dark:bg-gray-800 text-gray-600 dark:text-gray-400 hover:bg-gray-200 dark:hover:bg-gray-700"
                )}
              >
                {qt.label}
              </button>
            );
          })}
        </div>

        {/* Custom time input */}
        <div className="flex items-center gap-2">
          <Clock className="h-4 w-4 text-gray-400 dark:text-gray-500 shrink-0" />
          <div className="flex items-center gap-1 rounded-lg border border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800 px-2 py-1.5">
            {/* Hour */}
            <input
              type="number"
              min={1} max={12}
              value={hour}
              onChange={(e) => handleHourInput(e.target.value)}
              onBlur={(e) => setHour(pad(Math.min(12, Math.max(1, parseInt(e.target.value, 10) || 9))))}
              className="w-8 bg-transparent text-center text-sm font-semibold text-gray-900 dark:text-gray-100 focus:outline-none [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none"
            />
            <span className="text-gray-400 font-bold text-sm">:</span>
            {/* Minute */}
            <input
              type="number"
              min={0} max={59}
              value={minute}
              onChange={(e) => handleMinuteInput(e.target.value)}
              onBlur={(e) => setMinute(pad(Math.min(59, Math.max(0, parseInt(e.target.value, 10) || 0))))}
              className="w-8 bg-transparent text-center text-sm font-semibold text-gray-900 dark:text-gray-100 focus:outline-none [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none"
            />
          </div>
          {/* AM/PM toggle */}
          <div className="flex rounded-lg border border-gray-200 dark:border-gray-700 overflow-hidden">
            {(["AM", "PM"] as const).map((period) => (
              <button
                key={period}
                type="button"
                onClick={() => handlePeriodChange(period)}
                className={cn(
                  "px-2.5 py-1.5 text-xs font-semibold transition-colors",
                  ampm === period
                    ? "bg-blue-600 text-white"
                    : "bg-white dark:bg-gray-900 text-gray-500 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-800"
                )}
              >
                {period}
              </button>
            ))}
          </div>
        </div>
      </div>

      {/* ── Selected summary ── */}
      {selectedDate && (
        <div className="border-t border-gray-100 dark:border-gray-800 bg-blue-50 dark:bg-blue-950/30 px-4 py-2.5 flex items-center gap-2">
          <Calendar className="h-3.5 w-3.5 text-blue-500 shrink-0" />
          <p className="text-xs font-medium text-blue-700 dark:text-blue-300">
            {new Intl.DateTimeFormat("en-US", {
              weekday: "short", month: "short", day: "numeric",
              hour: "numeric", minute: "2-digit",
            }).format(mergeDateAndTime(selectedDate, hour, minute, ampm))}
          </p>
        </div>
      )}
    </div>
  );
}
