"use client";

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

// ─── Types ────────────────────────────────────────────────────────────────────
export interface DateTimeRange {
  start: Date | null;
  end:   Date | null;
}

interface ScheduleDateTimeRangeProps {
  value: DateTimeRange;
  onChange: (range: DateTimeRange) => void;
  error?: boolean;
}

// ─── Helpers ──────────────────────────────────────────────────────────────────
const MONTHS = ["January","February","March","April","May","June","July","August","September","October","November","December"];
const MONTHS_SHORT = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];

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

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

function formatTime(date: Date) {
  const h = toDisplayHour(date.getHours());
  const m = pad(date.getMinutes());
  const ap = date.getHours() >= 12 ? "pm" : "am";
  return `${h}:${m}${ap}`;
}

function formatDate(date: Date) {
  return `${MONTHS_SHORT[date.getMonth()]} ${date.getDate()}, ${date.getFullYear()}`;
}

function setTime(base: Date, h12: number, min: number, ampm: "am" | "pm"): Date {
  let h = h12;
  if (ampm === "pm" && h < 12) h += 12;
  if (ampm === "am" && h === 12) h = 0;
  return new Date(base.getFullYear(), base.getMonth(), base.getDate(), h, min, 0);
}

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

// ─── Calendar classnames ──────────────────────────────────────────────────────
const calCN: 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",
  [UI.Weekdays]: "border-0",
  [UI.Weekday]: "py-1.5 text-center text-[10px] font-semibold uppercase text-gray-400",
  [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 dark:text-gray-300 dark:hover:bg-gray-800",
  [SelectionState.selected]: "[&_.rdp-day_button]:bg-blue-600 [&_.rdp-day_button]:text-white [&_.rdp-day_button]:font-semibold",
  [DayFlag.today]: "[&_.rdp-day_button]:border [&_.rdp-day_button]:border-blue-400 [&_.rdp-day_button]:font-semibold [&_.rdp-day_button]:text-blue-600",
  [DayFlag.disabled]: "opacity-30 [&_.rdp-day_button]:cursor-not-allowed [&_.rdp-day_button]:hover:bg-transparent",
  [DayFlag.outside]: "opacity-0 pointer-events-none",
};

// ─── Time picker popover content ──────────────────────────────────────────────
interface TimePickerContentProps {
  hour: number;   // 1-12
  minute: number; // 0-59
  ampm: "am" | "pm";
  onChange: (h: number, m: number, ap: "am" | "pm") => void;
}

function TimePickerContent({ hour, minute, ampm, onChange }: TimePickerContentProps) {
  const hours   = Array.from({ length: 12 }, (_, i) => i + 1);
  const minutes = Array.from({ length: 60 }, (_, i) => i);

  const hourRef   = useRef<HTMLDivElement>(null);
  const minuteRef = useRef<HTMLDivElement>(null);

  // Scroll selected item into centre on open / value change
  useEffect(() => {
    hourRef.current
      ?.querySelector(`[data-selected="true"]`)
      ?.scrollIntoView({ block: "center" });
  }, [hour]);

  useEffect(() => {
    minuteRef.current
      ?.querySelector(`[data-selected="true"]`)
      ?.scrollIntoView({ block: "center" });
  }, [minute]);

  return (
    <div className="p-2 w-48">
      {/* Column headers */}
      <div className="flex gap-1 mb-1 px-1">
        <span className="flex-1 text-center text-[10px] font-semibold uppercase text-gray-400">Hr</span>
        <span className="flex-1 text-center text-[10px] font-semibold uppercase text-gray-400">Min</span>
        <span className="w-10 text-center text-[10px] font-semibold uppercase text-gray-400">AM/PM</span>
      </div>

      <div className="flex gap-1">
        {/* Hours — scrollable */}
        <div ref={hourRef} className="flex-1 h-44 overflow-y-auto space-y-0.5 pr-0.5">
          {hours.map((h) => (
            <button
              key={h}
              type="button"
              data-selected={hour === h}
              onClick={() => onChange(h, minute, ampm)}
              className={cn(
                "w-full rounded-md px-1 py-1.5 text-sm text-center font-medium transition-colors",
                hour === h
                  ? "bg-blue-600 text-white"
                  : "text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800"
              )}
            >
              {h}
            </button>
          ))}
        </div>

        {/* Minutes — full 0-59 scrollable */}
        <div ref={minuteRef} className="flex-1 h-44 overflow-y-auto space-y-0.5 pr-0.5">
          {minutes.map((m) => (
            <button
              key={m}
              type="button"
              data-selected={minute === m}
              onClick={() => onChange(hour, m, ampm)}
              className={cn(
                "w-full rounded-md px-1 py-1.5 text-sm text-center font-medium transition-colors",
                minute === m
                  ? "bg-blue-600 text-white"
                  : "text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800"
              )}
            >
              {pad(m)}
            </button>
          ))}
        </div>

        {/* AM / PM */}
        <div className="w-10 flex flex-col gap-1 pt-0.5">
          {(["am", "pm"] as const).map((ap) => (
            <button
              key={ap}
              type="button"
              onClick={() => onChange(hour, minute, ap)}
              className={cn(
                "rounded-md px-1 py-1.5 text-xs font-semibold uppercase transition-colors",
                ampm === ap
                  ? "bg-blue-600 text-white"
                  : "text-gray-500 hover:bg-gray-100 dark:hover:bg-gray-800"
              )}
            >
              {ap}
            </button>
          ))}
        </div>
      </div>
    </div>
  );
}

// ─── Date picker popover content ──────────────────────────────────────────────
interface DatePickerContentProps {
  selected: Date | null;
  onSelect: (d: Date) => void;
  minDate?: Date;
}

function DatePickerContent({ selected, onSelect, minDate }: DatePickerContentProps) {
  const now = new Date();
  const minDateToUse = minDate ?? new Date(now.getFullYear(), now.getMonth(), now.getDate());
  const startMonth = new Date(minDateToUse.getFullYear(), minDateToUse.getMonth());
  const endMonth   = new Date(now.getFullYear() + 2, 11);
  const [displayMonth, setDisplayMonth] = useState(
    new Date((selected ?? now).getFullYear(), (selected ?? now).getMonth())
  );
  const years = Array.from(
    { length: endMonth.getFullYear() - startMonth.getFullYear() + 1 },
    (_, i) => startMonth.getFullYear() + i
  );

  const canPrev = displayMonth > startMonth;
  const canNext = displayMonth < endMonth;

  return (
    <div className="p-3 w-64">
      {/* Month/year nav */}
      <div className="flex items-center justify-between mb-2">
        <button
          type="button"
          disabled={!canPrev}
          onClick={() => setDisplayMonth(new Date(displayMonth.getFullYear(), displayMonth.getMonth() - 1))}
          className="flex h-7 w-7 items-center justify-center rounded-lg text-gray-500 hover:bg-gray-100 disabled:opacity-30 dark:hover:bg-gray-800"
        >
          <ChevronLeft className="h-4 w-4" />
        </button>

        <div className="flex items-center gap-1.5">
          <select
            value={displayMonth.getMonth()}
            onChange={(e) => setDisplayMonth(new Date(displayMonth.getFullYear(), Number(e.target.value)))}
            className="rounded border border-gray-200 bg-white px-1.5 py-0.5 text-xs font-semibold text-gray-900 outline-none dark:border-gray-700 dark:bg-gray-900 dark:text-gray-100"
          >
            {MONTHS.map((m, i) => {
              const isPastMonth = displayMonth.getFullYear() === minDateToUse.getFullYear() && i < minDateToUse.getMonth();
              return (
                <option key={m} value={i} disabled={isPastMonth}>
                  {m}
                </option>
              );
            })}
          </select>
          <select
            value={displayMonth.getFullYear()}
            onChange={(e) => {
              const selectedYear = Number(e.target.value);
              let selectedMonth = displayMonth.getMonth();
              if (selectedYear === minDateToUse.getFullYear() && selectedMonth < minDateToUse.getMonth()) {
                selectedMonth = minDateToUse.getMonth();
              }
              setDisplayMonth(new Date(selectedYear, selectedMonth));
            }}
            className="rounded border border-gray-200 bg-white px-1.5 py-0.5 text-xs font-semibold text-gray-900 outline-none dark:border-gray-700 dark:bg-gray-900 dark:text-gray-100"
          >
            {years.map((y) => <option key={y} value={y}>{y}</option>)}
          </select>
        </div>

        <button
          type="button"
          disabled={!canNext}
          onClick={() => setDisplayMonth(new Date(displayMonth.getFullYear(), displayMonth.getMonth() + 1))}
          className="flex h-7 w-7 items-center justify-center rounded-lg text-gray-500 hover:bg-gray-100 disabled:opacity-30 dark:hover:bg-gray-800"
        >
          <ChevronRight className="h-4 w-4" />
        </button>
      </div>

      <DayPicker
        mode="single"
        selected={selected ?? undefined}
        onSelect={(d) => d && onSelect(d)}
        disabled={{ before: minDateToUse }}
        month={displayMonth}
        onMonthChange={setDisplayMonth}
        startMonth={startMonth}
        endMonth={endMonth}
        hideNavigation
        fixedWeeks
        showOutsideDays
        classNames={calCN}
      />
    </div>
  );
}

// ─── Popover wrapper ──────────────────────────────────────────────────────────
interface SegmentPopoverProps {
  open: boolean;
  onClose: () => void;
  children: React.ReactNode;
  content: React.ReactNode;
  align?: "left" | "center" | "right";
}

function SegmentPopover({ open, onClose, children, content, align = "left" }: SegmentPopoverProps) {
  const ref = useRef<HTMLDivElement>(null);

  useEffect(() => {
    if (!open) return;
    function handler(e: MouseEvent) {
      if (ref.current && !ref.current.contains(e.target as Node)) onClose();
    }
    document.addEventListener("mousedown", handler);
    return () => document.removeEventListener("mousedown", handler);
  }, [open, onClose]);

  return (
    <div ref={ref} className="relative">
      {children}
      {open && (
        <div className={cn(
          "absolute top-full mt-1.5 z-50 rounded-xl border border-gray-200 bg-white shadow-lg dark:border-gray-700 dark:bg-gray-900",
          align === "right" && "right-0",
          align === "center" && "left-1/2 -translate-x-1/2",
          align === "left" && "left-0",
        )}>
          {content}
        </div>
      )}
    </div>
  );
}

// ─── Segment button ───────────────────────────────────────────────────────────
function Segment({
  label, placeholder, active, onClick, error,
}: {
  label?: string; placeholder: string; active: boolean; onClick: () => void; error?: boolean;
}) {
  return (
    <button
      type="button"
      onClick={onClick}
      className={cn(
        "flex items-center rounded-lg border px-3 py-2 text-sm font-medium transition-all whitespace-nowrap",
        active
          ? "border-blue-500 bg-blue-50 text-blue-700 dark:bg-blue-950/40 dark:text-blue-300 ring-2 ring-blue-500/20"
          : label
          ? "border-gray-200 bg-white text-gray-800 hover:border-blue-300 hover:bg-gray-50 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-200"
          : "border-dashed border-gray-300 bg-white text-gray-400 hover:border-blue-300 dark:border-gray-600 dark:bg-gray-900",
        error && !label && "border-red-400"
      )}
    >
      {label ?? placeholder}
    </button>
  );
}

// ─── Main component ───────────────────────────────────────────────────────────
type ActiveSegment = "startDate" | "startTime" | "endTime" | null;

export function ScheduleDateTimeRange({ value, onChange, error }: ScheduleDateTimeRangeProps) {
  const [active, setActive] = useState<ActiveSegment>(null);

  const now = new Date();

  // Derive display values
  const startDate = value.start;
  const endDate   = value.end;

  const startH   = startDate ? toDisplayHour(startDate.getHours()) : 1;
  const startMin = startDate ? startDate.getMinutes() : 0;
  const startAp  = startDate ? (startDate.getHours() >= 12 ? "pm" : "am") as "am" | "pm" : "am";

  const endH   = endDate ? toDisplayHour(endDate.getHours()) : 2;
  const endMin = endDate ? endDate.getMinutes() : 0;
  const endAp  = endDate ? (endDate.getHours() >= 12 ? "pm" : "am") as "am" | "pm" : "am";

  const toggle = (seg: ActiveSegment) => setActive((prev) => prev === seg ? null : seg);

  // When start date is picked, keep existing time or default to next 15-min
  const handleStartDate = (d: Date) => {
    const base = startDate ?? roundToNext15(now);
    const next = setTime(d, startH, startMin, startAp);
    // Auto-set end = start + 1hr if no end yet
    const newEnd = endDate
      ? setTime(endDate.getDate() === d.getDate() && endDate.getMonth() === d.getMonth() ? endDate : d, endH, endMin, endAp)
      : new Date(next.getTime() + 60 * 60 * 1000);
    onChange({ start: next, end: newEnd });
    setActive("startTime");
  };

  const handleStartTime = (h: number, m: number, ap: "am" | "pm") => {
    const base = startDate ?? now;
    const next = setTime(base, h, m, ap);
    // Shift end by same delta if end exists
    const newEnd = endDate
      ? new Date(next.getTime() + (endDate.getTime() - (startDate?.getTime() ?? next.getTime())))
      : new Date(next.getTime() + 60 * 60 * 1000);
    onChange({ start: next, end: newEnd });
  };

  const handleEndTime = (h: number, m: number, ap: "am" | "pm") => {
    const base = endDate ?? startDate ?? now;
    const next = setTime(base, h, m, ap);
    onChange({ start: value.start, end: next });
  };

  // Duration label between times
  const durationLabel = (() => {
    if (!startDate || !endDate) return null;
    const diff = endDate.getTime() - startDate.getTime();
    if (diff <= 0) return null;
    const totalMin = Math.round(diff / 60000);
    const h = Math.floor(totalMin / 60);
    const m = totalMin % 60;
    if (h === 0) return `${m}m`;
    if (m === 0) return `${h}h`;
    return `${h}h ${m}m`;
  })();

  const minDate = new Date(now.getFullYear(), now.getMonth(), now.getDate());

  return (
    <div className="space-y-2">
      {/* ── The bar ── */}
      <div className="flex items-center gap-1.5 flex-wrap">

        {/* Start date */}
        <SegmentPopover
          open={active === "startDate"}
          onClose={() => setActive(null)}
          align="left"
          content={
            <DatePickerContent
              selected={startDate}
              onSelect={handleStartDate}
              minDate={minDate}
            />
          }
        >
          <Segment
            label={startDate ? formatDate(startDate) : undefined}
            placeholder="Start date"
            active={active === "startDate"}
            onClick={() => toggle("startDate")}
            error={error}
          />
        </SegmentPopover>

        {/* Start time */}
        <SegmentPopover
          open={active === "startTime"}
          onClose={() => setActive(null)}
          align="left"
          content={
            <TimePickerContent
              hour={startH} minute={startMin} ampm={startAp}
              onChange={handleStartTime}
            />
          }
        >
          <Segment
            label={startDate ? formatTime(startDate) : undefined}
            placeholder="Start time"
            active={active === "startTime"}
            onClick={() => toggle("startTime")}
            error={error && !!startDate}
          />
        </SegmentPopover>

        {/* "to" separator */}
        <span className="text-sm text-gray-400 dark:text-gray-500 px-0.5 select-none">to</span>

        {/* End time */}
        <SegmentPopover
          open={active === "endTime"}
          onClose={() => setActive(null)}
          align="center"
          content={
            <TimePickerContent
              hour={endH} minute={endMin} ampm={endAp}
              onChange={handleEndTime}
            />
          }
        >
          <Segment
            label={endDate ? formatTime(endDate) : undefined}
            placeholder="End time"
            active={active === "endTime"}
            onClick={() => toggle("endTime")}
          />
        </SegmentPopover>

        {/* Duration badge */}
        {durationLabel && (
          <span className="rounded-full bg-gray-100 dark:bg-gray-800 px-2.5 py-1 text-xs font-medium text-gray-500 dark:text-gray-400">
            {durationLabel}
          </span>
        )}
      </div>

      {/* End date display (read-only, derived from end time) */}
      {endDate && startDate && endDate.toDateString() !== startDate.toDateString() && (
        <p className="text-xs text-gray-400 dark:text-gray-500">
          Ends on <span className="font-medium text-gray-600 dark:text-gray-300">{formatDate(endDate)}</span>
        </p>
      )}
    </div>
  );
}
