// ============ TaskQuest — shared widgets ============
const { useState, useEffect, useRef, useMemo, useCallback } = React;

function Avatar({ who, size = "", className = "", style = {} }) {
  const r = window.TQ.ROLES[who];
  if (!r) return null;
  return (
    <div className={`avatar ${size} ${className}`} title={r.name}
      style={Object.assign({ background: r.color }, style)}>
      {r.initials}
    </div>
  );
}

// click-outside hook
function useClickOutside(ref, onClose, active) {
  useEffect(() => {
    if (!active) return;
    function handler(e) { if (ref.current && !ref.current.contains(e.target)) onClose(); }
    function esc(e) { if (e.key === "Escape") onClose(); }
    document.addEventListener("mousedown", handler);
    document.addEventListener("keydown", esc);
    return () => { document.removeEventListener("mousedown", handler); document.removeEventListener("keydown", esc); };
  }, [active]);
}

// Calendar picker — restricted to today+ by default
function Calendar({ value, onChange, min }) {
  const { TODAY, parseISO } = window.TQ;
  const init = value ? parseISO(value) : new Date(TODAY);
  const [view, setView] = useState(new Date(init.getFullYear(), init.getMonth(), 1));
  const minDate = min ? parseISO(min) : null;

  const year = view.getFullYear(), month = view.getMonth();
  const first = new Date(year, month, 1);
  const startDow = first.getDay();
  const daysInMonth = new Date(year, month + 1, 0).getDate();
  const cells = [];
  for (let i = 0; i < startDow; i++) cells.push(null);
  for (let d = 1; d <= daysInMonth; d++) cells.push(d);

  function iso(d) {
    const m = String(month + 1).padStart(2, "0"), dd = String(d).padStart(2, "0");
    return `${year}-${m}-${dd}`;
  }
  const todayIso = `${TODAY.getFullYear()}-${String(TODAY.getMonth()+1).padStart(2,"0")}-${String(TODAY.getDate()).padStart(2,"0")}`;

  return (
    <div className="cal">
      <div className="cal-head">
        <button className="cal-nav" onClick={() => setView(new Date(year, month - 1, 1))}><Ic.ChevLeft size={16} /></button>
        <div className="cal-month">{view.toLocaleDateString("en-US", { month: "long", year: "numeric" })}</div>
        <button className="cal-nav" onClick={() => setView(new Date(year, month + 1, 1))}><Ic.ChevRight size={16} /></button>
      </div>
      <div className="cal-grid">
        {["S","M","T","W","T","F","S"].map((d, i) => <div key={i} className="cal-dow">{d}</div>)}
        {cells.map((d, i) => {
          if (d === null) return <div key={i} />;
          const cellIso = iso(d);
          const cellDate = new Date(year, month, d);
          const disabled = minDate && cellDate < minDate;
          const sel = value === cellIso;
          const isToday = cellIso === todayIso;
          return (
            <div key={i}
              className={`cal-day ${sel ? "sel" : ""} ${isToday && !sel ? "today" : ""} ${disabled ? "disabled" : ""}`}
              onClick={() => !disabled && onChange(cellIso)}>
              {d}
            </div>
          );
        })}
      </div>
    </div>
  );
}

// Searchable single-select — type to filter a long list of people/options.
// options: array of keys; getLabel(key)->string; renderOption(key)->JSX node.
function SearchableSelect({ options, value, onChange, getLabel, renderOption, placeholder = "Search…", emptyText = "No matches" }) {
  const [open, setOpen] = useState(false);
  const [q, setQ] = useState("");
  const ref = useRef(null);
  useClickOutside(ref, () => { setOpen(false); setQ(""); }, open);
  const filtered = options.filter(o => getLabel(o).toLowerCase().includes(q.trim().toLowerCase()));
  return (
    <div className="ssel" ref={ref}>
      <button type="button" className="ssel-trigger" onClick={() => setOpen(o => !o)}>
        <span className="ssel-cur">
          {value ? (renderOption ? renderOption(value) : getLabel(value)) : <span className="ssel-ph">{placeholder}</span>}
        </span>
        <Ic.ChevDown size={15} className="chev" />
      </button>
      {open && (
        <div className="ssel-pop">
          <div className="ssel-search">
            <Ic.Search size={14} style={{ color: "var(--faint)" }} />
            <input className="ssel-input" autoFocus placeholder={placeholder} value={q}
              onChange={e => setQ(e.target.value)} />
          </div>
          <div className="ssel-list">
            {filtered.length === 0 && <div className="ssel-empty">{emptyText}</div>}
            {filtered.map(o => (
              <button type="button" key={o}
                className={`ssel-opt ${value === o ? "sel" : ""}`}
                onClick={() => { onChange(o); setOpen(false); setQ(""); }}>
                <span className="ssel-opt-c">{renderOption ? renderOption(o) : getLabel(o)}</span>
                {value === o && <span className="ssel-check"><Ic.Check size={15} /></span>}
              </button>
            ))}
          </div>
        </div>
      )}
    </div>
  );
}

// Compact date field — shows the selected date as a field and opens the
// calendar in a popover on click (instead of an always-open month grid).
function DateField({ value, onChange, min, placeholder = "Select a date" }) {
  const { fmtDateLong } = window.TQ;
  const [open, setOpen] = useState(false);
  const ref = useRef(null);
  useClickOutside(ref, () => setOpen(false), open);
  return (
    <div className="datefield" ref={ref}>
      <button type="button" className="datefield-trigger" onClick={() => setOpen(o => !o)}>
        <Ic.Calendar size={15} style={{ color: "var(--faint)" }} />
        <span className={value ? "df-val" : "df-ph"}>{value ? fmtDateLong(value) : placeholder}</span>
        <Ic.ChevDown size={14} className="chev" />
      </button>
      {open && (
        <div className="datefield-pop">
          <Calendar value={value} onChange={(v) => { onChange(v); setOpen(false); }} min={min} />
        </div>
      )}
    </div>
  );
}

// Toasts
function ToastHost({ toasts }) {
  return (
    <div className="toast-wrap">
      {toasts.map(t => (
        <div className="toast" key={t.id}>
          <div className="toast-ic" style={{ background: t.color + "22", color: t.color }}>
            {t.icon ? React.createElement(t.icon, { size: 14 }) : <Ic.Check size={14} />}
          </div>
          {t.text}
        </div>
      ))}
    </div>
  );
}

window.Avatar = Avatar;
window.useClickOutside = useClickOutside;
window.Calendar = Calendar;
window.DateField = DateField;
window.SearchableSelect = SearchableSelect;
window.ToastHost = ToastHost;
