"use client";

// Jalali (Shamsi) date picker. The `value`/`onChange` wire format stays the ISO
// Gregorian `YYYY-MM-DD` the API expects — only the UI is Persian-calendar.
// For the `en` locale it falls back to the native Gregorian date input.

import { useEffect, useMemo, useRef, useState } from "react";
import { useLocale } from "next-intl";
import {
  addMonths,
  eachDayOfInterval,
  endOfMonth,
  endOfWeek,
  format as formatJalali,
  isSameDay,
  isSameMonth,
  parseISO,
  startOfMonth,
  startOfWeek,
} from "date-fns-jalali";
import { faIR } from "date-fns-jalali/locale/fa-IR";
import { CalendarDays, ChevronLeft, ChevronRight } from "lucide-react";
import { Input } from "@/components/ui/input";
import { cn } from "@/lib/utils";

const FA_DIGITS = "۰۱۲۳۴۵۶۷۸۹";
const AR_DIGITS = "٠١٢٣٤٥٦٧٨٩";

function localizeDigits(s: string, locale: string): string {
  if (locale === "en") return s;
  const digits = locale === "ar" ? AR_DIGITS : FA_DIGITS;
  return s.replace(/\d/g, (d) => digits[Number(d)]!);
}

/** Gregorian ISO date (YYYY-MM-DD) from a local Date — no UTC shift. */
function toIsoDate(d: Date): string {
  return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(
    d.getDate()
  ).padStart(2, "0")}`;
}

/** Saturday-first week, the Iranian convention. */
const WEEK_STARTS_ON = 6 as const;
const FA_WEEKDAYS = ["ش", "ی", "د", "س", "چ", "پ", "ج"];

export function JalaliDateField({
  id,
  value,
  onChange,
  className,
  placeholder,
}: {
  id?: string;
  /** ISO Gregorian date string (YYYY-MM-DD) or "". */
  value: string;
  onChange: (iso: string) => void;
  className?: string;
  placeholder?: string;
}) {
  const locale = useLocale();
  const [open, setOpen] = useState(false);
  const selected = useMemo(() => (value ? parseISO(value) : null), [value]);
  const [viewDate, setViewDate] = useState<Date>(() => selected ?? new Date());
  const rootRef = useRef<HTMLDivElement>(null);

  // Keep the visible month in sync when the value changes externally.
  useEffect(() => {
    if (selected) setViewDate(selected);
  }, [selected]);

  useEffect(() => {
    if (!open) return;
    const onDown = (e: MouseEvent) => {
      if (rootRef.current && !rootRef.current.contains(e.target as Node)) {
        setOpen(false);
      }
    };
    document.addEventListener("mousedown", onDown);
    return () => document.removeEventListener("mousedown", onDown);
  }, [open]);

  // English UI keeps the familiar native Gregorian picker.
  if (locale === "en") {
    return (
      <Input
        id={id}
        type="date"
        value={value}
        onChange={(e) => onChange(e.target.value)}
        dir="ltr"
        className={cn("text-end", className)}
      />
    );
  }

  const days = eachDayOfInterval({
    start: startOfWeek(startOfMonth(viewDate), { weekStartsOn: WEEK_STARTS_ON }),
    end: endOfWeek(endOfMonth(viewDate), { weekStartsOn: WEEK_STARTS_ON }),
  });
  const today = new Date();
  const label = selected
    ? localizeDigits(formatJalali(selected, "yyyy/MM/dd"), locale)
    : (placeholder ?? "");
  const monthTitle = localizeDigits(
    formatJalali(viewDate, "MMMM yyyy", { locale: faIR }),
    locale
  );

  return (
    <div ref={rootRef} className="relative">
      <button
        id={id}
        type="button"
        onClick={() => setOpen((v) => !v)}
        aria-haspopup="dialog"
        aria-expanded={open}
        className={cn(
          "flex h-10 w-full cursor-pointer items-center justify-between gap-2 rounded-md border border-input bg-background px-3 py-2 text-sm transition-colors",
          "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
          !selected && "text-muted-foreground",
          className
        )}
      >
        <span className="truncate">{label || "—"}</span>
        <CalendarDays className="h-4 w-4 shrink-0 text-muted-foreground" aria-hidden />
      </button>

      {open && (
        <div
          role="dialog"
          className="absolute z-50 mt-1 w-64 rounded-xl border border-border bg-popover p-2 shadow-lg start-0"
        >
          {/* Month header */}
          <div className="mb-1 flex items-center justify-between">
            <button
              type="button"
              onClick={() => setViewDate((d) => addMonths(d, -1))}
              aria-label="ماه قبل"
              className="flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg text-muted-foreground transition-colors hover:bg-accent hover:text-foreground"
            >
              <ChevronRight className="h-4 w-4 rtl:block ltr:hidden" aria-hidden />
              <ChevronLeft className="h-4 w-4 rtl:hidden ltr:block" aria-hidden />
            </button>
            <span className="text-sm font-semibold">{monthTitle}</span>
            <button
              type="button"
              onClick={() => setViewDate((d) => addMonths(d, 1))}
              aria-label="ماه بعد"
              className="flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg text-muted-foreground transition-colors hover:bg-accent hover:text-foreground"
            >
              <ChevronLeft className="h-4 w-4 rtl:block ltr:hidden" aria-hidden />
              <ChevronRight className="h-4 w-4 rtl:hidden ltr:block" aria-hidden />
            </button>
          </div>

          {/* Weekday header */}
          <div className="grid grid-cols-7 text-center">
            {FA_WEEKDAYS.map((w) => (
              <span key={w} className="py-1 text-[10px] font-semibold text-muted-foreground">
                {w}
              </span>
            ))}
          </div>

          {/* Day grid */}
          <div className="grid grid-cols-7">
            {days.map((day) => {
              const inMonth = isSameMonth(day, viewDate);
              const isSelected = selected ? isSameDay(day, selected) : false;
              const isToday = isSameDay(day, today);
              return (
                <button
                  key={day.getTime()}
                  type="button"
                  onClick={() => {
                    onChange(toIsoDate(day));
                    setOpen(false);
                  }}
                  className={cn(
                    "flex h-8 cursor-pointer items-center justify-center rounded-lg text-xs transition-colors",
                    inMonth ? "text-foreground" : "text-muted-foreground/40",
                    isSelected
                      ? "bg-primary font-bold text-primary-foreground"
                      : isToday
                        ? "border border-primary/50 font-semibold text-primary hover:bg-accent"
                        : "hover:bg-accent"
                  )}
                >
                  {localizeDigits(formatJalali(day, "d"), locale)}
                </button>
              );
            })}
          </div>

          {/* Today shortcut */}
          <button
            type="button"
            onClick={() => {
              onChange(toIsoDate(today));
              setViewDate(today);
              setOpen(false);
            }}
            className="mt-1 w-full cursor-pointer rounded-lg py-1.5 text-center text-xs font-medium text-primary transition-colors hover:bg-accent"
          >
            امروز
          </button>
        </div>
      )}
    </div>
  );
}

/** Format an ISO Gregorian date string as a Jalali date for display. */
export function formatIsoDateJalali(iso: string, locale: string): string {
  if (locale === "en") return iso;
  try {
    return localizeDigits(formatJalali(parseISO(iso), "yyyy/MM/dd"), locale);
  } catch {
    return iso;
  }
}
