/* ---------- One date, with month and year pickable directly ----------
   The native date input buries month and year behind the calendar's arrows, so
   a hire date a few years back costs dozens of clicks. Popover mechanics are
   SearchSelect's — fixed position measured off the trigger — so the calendar
   escapes the modal's clipping instead of being cut off by it, and the day
   grid reuses the range picker's .drp-* styling so both calendars match. */
function DateField({ value, onChange, placeholder, disabled, clearable }) {
  const { useState, useEffect, useRef } = React;
  const rootRef = useRef(null);
  const [open, setOpen] = useState(false);
  const [pos, setPos] = useState(null);

  const iso = (d) => d.getFullYear() + "-" + String(d.getMonth() + 1).padStart(2, "0") + "-" + String(d.getDate()).padStart(2, "0");
  const parse = (s) => { if (!s) return null; const d = new Date(String(s).slice(0, 10) + "T00:00:00"); return isNaN(d) ? null : d; };
  const now = new Date();
  const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
  const sel = parse(value);
  const [view, setView] = useState(sel || today);
  // Reopening lands on the value's month, not wherever the last browse ended.
  useEffect(() => { if (open) setView(parse(value) || today); }, [open]);

  const POP_W = 268;
  const place = () => {
    const el = rootRef.current;
    if (!el) return;
    const r = el.getBoundingClientRect();
    const vh = window.innerHeight;
    const w = Math.max(r.width, POP_W);
    // The field sits against either edge depending on the language, so clamp
    // rather than assuming it opens rightwards.
    const left = Math.max(8, Math.min(r.left, window.innerWidth - w - 8));
    const below = vh - r.bottom;
    setPos(below < 330 && r.top > below
      ? { left: left, width: w, bottom: vh - r.top + 6 }
      : { left: left, width: w, top: r.bottom + 6 });
  };

  useEffect(() => {
    if (!open) return;
    place();
    const onDown = (e) => { if (rootRef.current && !rootRef.current.contains(e.target)) setOpen(false); };
    const onKey = (e) => { if (e.key === "Escape") setOpen(false); };
    const onMove = () => place();
    document.addEventListener("mousedown", onDown);
    window.addEventListener("keydown", onKey);
    window.addEventListener("scroll", onMove, true);
    window.addEventListener("resize", onMove);
    return () => {
      document.removeEventListener("mousedown", onDown);
      window.removeEventListener("keydown", onKey);
      window.removeEventListener("scroll", onMove, true);
      window.removeEventListener("resize", onMove);
    };
  }, [open]);

  const addDays = (d, n) => { const x = new Date(d); x.setDate(x.getDate() + n); return x; };
  const monWeekStart = (d) => addDays(d, -((d.getDay() + 6) % 7)); // Monday first, as in DateRangePicker
  const y = view.getFullYear(), m = view.getMonth();
  const cells = Array.from({ length: 42 }, (_, i) => addDays(monWeekStart(new Date(y, m, 1)), i));
  const shift = (n) => setView(new Date(y, m + n, 1));
  const pick = (d) => { onChange(iso(d)); setOpen(false); };

  // Months as numbers: a list of twelve Arabic names is a tall scroll to read
  // through, while 1–12 is one glance and keeps the header narrow.
  const months = Array.from({ length: 12 }, (_, i) => i + 1);
  // Wide enough for a hire date decades back and a long fixed term ahead, and
  // always wide enough to hold the date already on file.
  const selY = sel ? sel.getFullYear() : y;
  const y0 = Math.min(today.getFullYear() - 50, selY, y);
  const y1 = Math.max(today.getFullYear() + 20, selY, y);
  const years = Array.from({ length: y1 - y0 + 1 }, (_, i) => y0 + i);

  // dd/mm/yyyy in both languages: the locale's own order puts the month name
  // first in English and spells it out in Arabic, so build the parts by hand
  // and the same field reads the same way whichever language is on.
  const label = sel ? String(sel.getDate()).padStart(2, "0") + "/" + String(sel.getMonth() + 1).padStart(2, "0") + "/" + sel.getFullYear() : "";

  return (
    <div className="df" ref={rootRef}>
      <button type="button" className={"input df-field" + (disabled ? " disabled" : "") + (open ? " on" : "")}
        disabled={disabled} onClick={() => setOpen((o) => !o)}>
        <span className={label ? "" : "dim"}>{label || placeholder || T("common.choose")}</span>
        <Icon name="calendar" size={15} />
      </button>
      {/* Field renders a <label>, which forwards stray clicks to its control —
          our trigger — and would toggle the popup shut again. Cancelling the
          click cancels that forwarding. preventDefault on click only: on
          mousedown it would stop the month/year menus from opening. */}
      {open ? (
        <div className="df-pop" style={pos || { visibility: "hidden" }} onClick={(e) => e.preventDefault()}>
          <div className="df-head">
            <button type="button" className="df-nav prev" onClick={() => shift(-1)} aria-label={T("date.prevMonth")}>
              <Icon name="chevR" size={14} />
            </button>
            <select className="df-sel df-num" value={m} onChange={(e) => setView(new Date(y, +e.target.value, 1))}>
              {months.map((n, i) => <option key={i} value={i}>{n}</option>)}
            </select>
            <select className="df-sel df-num df-year" value={y} onChange={(e) => setView(new Date(+e.target.value, m, 1))}>
              {years.map((yr) => <option key={yr} value={yr}>{yr}</option>)}
            </select>
            <button type="button" className="df-nav next" onClick={() => shift(1)} aria-label={T("date.nextMonth")}>
              <Icon name="chevR" size={14} />
            </button>
          </div>
          <div className="drp-grid df-grid">
            {Array.from({ length: 7 }, (_, i) => addDays(monWeekStart(new Date(y, m, 1)), i)).map((d, i) => (
              <span key={i} className="drp-dow">{d.toLocaleDateString(uiLocale(), { weekday: "short" })}</span>
            ))}
            {cells.map((d, i) => (
              <button key={i} type="button"
                // Compared as ISO, not as timestamps: a DST change inside the
                // visible grid shifts the clock and no two dates would match.
                className={"drp-day" + (d.getMonth() !== m ? " out" : "")
                  + (sel && iso(d) === iso(sel) ? " edge" : "") + (iso(d) === iso(today) ? " today" : "")}
                onClick={() => pick(d)}>{d.getDate()}</button>
            ))}
          </div>
          {/* Clear is opt-in: on a field the record can't do without, an empty
              date is a save that fails at the server, not a choice. */}
          <div className="df-foot">
            {clearable
              ? <button type="button" className="df-act" onClick={() => { onChange(""); setOpen(false); }}>{T("common.clear")}</button>
              : <span></span>}
            <button type="button" className="df-act strong" onClick={() => pick(today)}>{T("date.today")}</button>
          </div>
        </div>
      ) : null}
    </div>
  );
}
window.DateField = DateField;
