/* ui.jsx — primitives, filter controls, nav */
const { D, fmt, fmtSign, pct, monthLabel, Icon, Ico, ICONS, slVar } = window.RX;

/* localStorage hook */
function useLS(key, init) {
  const [v, setV] = useState(() => {
    try { const s = localStorage.getItem(key); return s != null ? JSON.parse(s) : init; }
    catch (e) { return init; }
  });
  useEffect(() => { try { localStorage.setItem(key, JSON.stringify(v)); } catch (e) {} }, [key, v]);
  return [v, setV];
}

/* outside-click */
function useOutside(ref, onClose, active) {
  useEffect(() => {
    if (!active) return;
    const h = (e) => { if (ref.current && !ref.current.contains(e.target)) onClose(); };
    const k = (e) => { if (e.key === "Escape") onClose(); };
    document.addEventListener("mousedown", h); document.addEventListener("keydown", k);
    return () => { document.removeEventListener("mousedown", h); document.removeEventListener("keydown", k); };
  }, [active]);
}

/* ---------- Card ---------- */
function Card({ title, desc, meta, right, children, style, pad }) {
  return (
    <div className="card" style={style}>
      {(title || right) &&
        <div className="card-h">
          <div>
            {title && <div className="t">{title}</div>}
            {desc && <div className="d">{desc}</div>}
          </div>
          <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
            {meta && <div className="meta">{meta}</div>}
            {right}
          </div>
        </div>}
      {children}
    </div>
  );
}

/* unified-model fallback — production wording, used wherever a card's data is null */
function Unavail({ what }) {
  return <div className="empty"><b>Unified model unavailable.</b><br />
    {what} did not build on the last data refresh and will return on the next successful one.</div>;
}

/* ---------- KPI ---------- */
function Delta({ value, suffix, invert }) {
  if (value == null) return null;
  const good = invert ? value < 0 : value > 0;
  const cls = value === 0 ? "flat" : good ? "pos" : "neg";
  return (
    <span className={"delta " + cls}>
      {value !== 0 && <Ico size={13} d={value > 0 ? ICONS.arrowUp : ICONS.arrowDn} />}
      {fmtSign(value)}{suffix}
    </span>
  );
}
function KPI({ label, value, sub, delta, deltaSuffix, invert, tip, feature, accentBar, valClass, children }) {
  return (
    <div className={"kpi" + (feature ? " feature" : "")} style={accentBar ? { borderTop: "2px solid " + accentBar } : null}>
      <div className="lab">{label}{tip && <span className="tip" title={tip}>?</span>}</div>
      <div className={"val " + (valClass || "")}>{value}</div>
      <div style={{ display: "flex", alignItems: "center", gap: 9, flexWrap: "wrap" }}>
        {delta != null && <Delta value={delta} suffix={deltaSuffix} invert={invert} />}
        {sub && <span className="sub">{sub}</span>}
      </div>
      {children}
    </div>
  );
}

/* ---------- Segmented ---------- */
function Segmented({ value, options, onChange }) {
  return (
    <div className="seg">
      {options.map(o => {
        const val = o.value !== undefined ? o.value : o;
        const lab = o.label !== undefined ? o.label : o;
        return <button key={val} data-on={value === val ? "1" : "0"} onClick={() => onChange(val)}>{lab}</button>;
      })}
    </div>
  );
}

/* ---------- Date filter (presets + custom) ---------- */
function DateFilter({ raw, onChange }) {
  const [open, setOpen] = useState(false);
  const ref = useRef();
  useOutside(ref, () => setOpen(false), open);
  const presetLabel = (window.RX.PRESETS.find(p => p[0] === raw.preset) || [])[1];
  const label = raw.preset === "custom" || !presetLabel
    ? window.RX.fmtDate(raw.from) + " – " + window.RX.fmtDate(raw.to)
    : presetLabel;
  const pick = (key) => { const r = window.RX.resolvePreset(key); onChange({ from: r.from, to: r.to, preset: key }); setOpen(false); };
  return (
    <div ref={ref} style={{ position: "relative" }}>
      <button className={"ctrl" + (raw.preset === "all" ? "" : " on")} onClick={() => setOpen(o => !o)}>
        <Ico size={14} d={ICONS.cal} />
        <span className="cap">Date</span><span className="v">{label}</span>
        <span className="chev"><Ico size={13} d={ICONS.chev} /></span>
      </button>
      {open &&
        <div className="pop" style={{ minWidth: 230 }}>
          <div className="pop-h"><b>Date range</b></div>
          {window.RX.PRESETS.map(([k, lab]) => (
            <div key={k} className="opt" data-on={raw.preset === k ? "1" : "0"} onClick={() => pick(k)}>
              <span className="box" style={{ borderRadius: 20 }}><Ico size={12} d={ICONS.check} stroke="#fff" /></span>
              <span className="nm">{lab}</span>
            </div>
          ))}
          <div className="divider" />
          <div style={{ padding: "4px 9px 8px" }}>
            <div style={{ fontSize: 11, color: "var(--text-3)", textTransform: "uppercase", letterSpacing: ".05em", fontWeight: 600, marginBottom: 7 }}>Custom</div>
            <div style={{ display: "flex", gap: 7, alignItems: "center" }}>
              <input type="date" className="dateinput" value={raw.from} min={D.data_window.first} max={D.data_window.last}
                onChange={e => onChange({ from: e.target.value, to: raw.to < e.target.value ? e.target.value : raw.to, preset: "custom" })} />
              <span style={{ color: "var(--text-3)" }}>→</span>
              <input type="date" className="dateinput" value={raw.to} min={D.data_window.first} max={D.data_window.last}
                onChange={e => onChange({ from: raw.from > e.target.value ? e.target.value : raw.from, to: e.target.value, preset: "custom" })} />
            </div>
          </div>
        </div>}
    </div>
  );
}

/* ---------- Month range (kept for reference, unused) ---------- */
function MonthRange({ from, to, onChange }) {
  return (
    <div className="mrange">
      <select value={from} onChange={e => { const f = +e.target.value; onChange(Math.min(f, to), to); }}>
        {D.months.map((m, i) => <option key={i} value={i}>{monthLabel(m)}</option>)}
      </select>
      <span className="arr">→</span>
      <select value={to} onChange={e => { const t = +e.target.value; onChange(from, Math.max(t, from)); }}>
        {D.months.map((m, i) => <option key={i} value={i}>{monthLabel(m)}</option>)}
      </select>
    </div>
  );
}

/* ---------- Payer multi-select ---------- */
function PayerSelect({ selected, onChange, counts }) {
  const [open, setOpen] = useState(false);
  const ref = useRef();
  useOutside(ref, () => setOpen(false), open);
  const n = selected.size, total = D.payers.length;
  const allOn = n === total;
  const toggle = (i) => { const s = new Set(selected); s.has(i) ? s.delete(i) : s.add(i); if (s.size) onChange(s); };
  const order = D.payers.map((p, i) => i).sort((a, b) => (counts ? counts[b] - counts[a] : 0));
  return (
    <div ref={ref} style={{ position: "relative" }}>
      <button className={"ctrl" + (allOn ? "" : " on")} onClick={() => setOpen(o => !o)}>
        <span className="cap">Payer</span>
        <span className="v">{allOn ? "All" : n + " selected"}</span>
        {!allOn && <span className="cnt-badge">{n}</span>}
        <span className="chev"><Ico size={13} d={ICONS.chev} /></span>
      </button>
      {open &&
        <div className="pop" style={{ minWidth: 270, maxHeight: 360, overflowY: "auto" }}>
          <div className="pop-h">
            <b>Payers</b>
            <a onClick={() => onChange(new Set(D.payers.map((_, i) => i)))}>Select all</a>
          </div>
          {order.map(i => {
            const p = D.payers[i];
            return (
              <div key={i} className="opt" data-on={selected.has(i) ? "1" : "0"} onClick={() => toggle(i)}>
                <span className="box"><Ico size={12} d={ICONS.check} stroke="#fff" /></span>
                <span className="nm">{p.name}{p.pb && <span className="pb"> · paper</span>}</span>
                {counts && <span className="ct">{fmt(counts[i])}</span>}
              </div>
            );
          })}
        </div>}
    </div>
  );
}

/* ---------- Product multi-select: Line -> Brand/Family -> Item ---------- */
function ProductSelect({ selected, onChange, counts }) {
  const [open, setOpen] = useState(false);
  const [q, setQ] = useState("");
  const [expanded, setExpanded] = useState({});       // family -> bool
  const ref = useRef();
  useOutside(ref, () => setOpen(false), open);
  const n = selected.size, total = D.drugs.length, allOn = n === total;

  const groups = useMemo(() => {
    const g = {};
    D.drugs.forEach((d, i) => {
      const fam = d.family || "Other";
      (((g[d.line] = g[d.line] || {})[fam] = g[d.line][fam] || [])).push(i);
    });
    return D.lines.filter(l => g[l]).map(l => ({
      line: l,
      fams: Object.entries(g[l]).map(([fam, idx]) => ({
        fam, idx, total: idx.reduce((a, i) => a + D.drugs[i].total, 0),
      })).sort((a, b) => b.total - a.total),
    }));
  }, []);

  const setMany = (idx, on) => {
    const s = new Set(selected);
    idx.forEach(i => on ? s.add(i) : s.delete(i));
    if (s.size) onChange(s);
  };
  const famState = (idx) => { const k = idx.filter(i => selected.has(i)).length; return k === 0 ? 0 : k === idx.length ? 2 : 1; };
  const match = q.trim().toUpperCase();
  const hits = match ? D.drugs.map((d, i) => i).filter(i =>
    D.drugs[i].name.toUpperCase().includes(match) || (D.drugs[i].family || "").toUpperCase().includes(match)) : null;

  const ItemRow = ({ i }) => (
    <div className="opt" data-on={selected.has(i) ? "1" : "0"} onClick={() => setMany([i], !selected.has(i))} style={{ paddingLeft: 26 }}>
      <span className="box"><Ico size={12} d={ICONS.check} stroke="#fff" /></span>
      <span className="nm" title={D.drugs[i].name}>{D.drugs[i].name.length > 30 ? D.drugs[i].name.slice(0, 30) + "…" : D.drugs[i].name}</span>
      {counts && <span className="ct">{fmt(counts[i])}</span>}
    </div>);

  return (
    <div ref={ref} style={{ position: "relative" }}>
      <button className={"ctrl" + (allOn ? "" : " on")} onClick={() => setOpen(o => !o)}>
        <span className="cap">Product</span>
        <span className="v">{allOn ? "All" : n + " selected"}</span>
        {!allOn && <span className="cnt-badge">{n}</span>}
        <span className="chev"><Ico size={13} d={ICONS.chev} /></span>
      </button>
      {open &&
        <div className="pop" style={{ minWidth: 320, maxHeight: 420, overflowY: "auto" }}>
          <div className="pop-h">
            <b>Products</b>
            <a onClick={() => onChange(new Set(D.drugs.map((_, i) => i)))}>Select all</a>
          </div>
          <div style={{ padding: "2px 9px 7px" }}>
            <input className="dateinput" style={{ width: "100%" }} placeholder="Search item or brand…"
              value={q} onChange={e => setQ(e.target.value)} />
          </div>
          {hits && <>{hits.length ? hits.map(i => <ItemRow key={i} i={i} />)
            : <div className="empty">No products match.</div>}</>}
          {!hits && groups.map(({ line, fams }) => (
            <React.Fragment key={line}>
              <div className="pop-h" style={{ paddingTop: 7 }}>
                <b style={{ display: "inline-flex", alignItems: "center", gap: 7 }}>
                  <span className="sw" style={{ background: slVar(line), width: 8, height: 8, borderRadius: 2, display: "inline-block" }} />{line}</b>
              </div>
              {fams.map(({ fam, idx }) => {
                const st = famState(idx), exp = !!expanded[fam + line];
                return (
                  <React.Fragment key={fam}>
                    <div className="opt" data-on={st === 2 ? "1" : "0"} onClick={() => setMany(idx, st !== 2)}>
                      <span className="box" style={st === 1 ? { background: "var(--accent)", opacity: .45 } : null}>
                        <Ico size={12} d={ICONS.check} stroke="#fff" /></span>
                      <span className="nm"><b>{fam}</b> <span style={{ color: "var(--text-3)" }}>· {idx.length}</span></span>
                      <a style={{ marginLeft: "auto", fontSize: 11 }}
                        onClick={e => { e.stopPropagation(); setExpanded(x => ({ ...x, [fam + line]: !exp })); }}>
                        <Ico size={12} d={exp ? ICONS.chev : ICONS.chevR} /></a>
                    </div>
                    {exp && idx.map(i => <ItemRow key={i} i={i} />)}
                  </React.Fragment>);
              })}
            </React.Fragment>))}
        </div>}
    </div>
  );
}

/* ---------- Service-line chips ---------- */
function LineChips({ selected, onChange, counts }) {
  const toggle = (l) => { const s = new Set(selected); s.has(l) ? s.delete(l) : s.add(l); if (s.size) onChange(s); };
  return (
    <div className="chips">
      {D.lines.map(l => (
        <button key={l} className="chip" data-on={selected.has(l) ? "1" : "0"} onClick={() => toggle(l)}>
          <span className="sw" style={{ background: slVar(l) }} />
          {l}{counts && <span style={{ color: "var(--text-3)", fontVariantNumeric: "tabular-nums" }}>{fmt(counts[l])}</span>}
        </button>
      ))}
    </div>
  );
}

/* ---------- Paper-bill lens ---------- */
const PB_OPTS = [
  { value: "all", label: "All payers" },
  { value: "xent", label: "Excl. enteral paper" },
  { value: "xpb", label: "Excl. all paper" },
];
function PaperBillLens({ value, onChange }) {
  return <Segmented value={value} options={PB_OPTS} onChange={onChange} />;
}

/* ---------- Nav ---------- */
const NAV = [
  { key: "fold", label: "Front fold", icon: "overview", group: "Dashboard" },
  { key: "overview", label: "Overview", icon: "overview", group: "Dashboard" },
  { key: "mix", label: "Product Mix", icon: "mix", group: "Dashboard" },
  { key: "patients", label: "Patients", icon: "patients", group: "Dashboard" },
  { key: "forecast", label: "Forecast", icon: "forecast", group: "Dashboard" },
  { key: "verification", label: "Onboarding/Verification", icon: "verify", group: "Department" },
  { key: "refill", label: "Refill", icon: "refill", group: "Department" },
  { key: "shipping", label: "Shipping", icon: "truck", group: "Department" },
  { key: "fillers", label: "Fillers", icon: "pill", group: "Department" },
  { key: "projects", label: "Projects", icon: "layers", group: "Initiatives" },
];
function Sidebar({ view, setView, tags }) {
  const groups = [];
  NAV.forEach(n => { let g = groups.find(x => x.name === n.group); if (!g) { g = { name: n.group, items: [] }; groups.push(g); } g.items.push(n); });
  return (
    <nav className="side">
      {groups.map(g => (
        <React.Fragment key={g.name}>
          <div className="grp">{g.name}</div>
          {g.items.map(n => (
            <button key={n.key} data-on={view === n.key ? "1" : "0"} onClick={() => setView(n.key)}>
              <Icon name={n.icon} size={17} /> {n.label}
              {tags[n.key] && <span className="nav-tag">{tags[n.key]}</span>}
            </button>
          ))}
        </React.Fragment>
      ))}
      <div className="side-foot">
        ExpressRx Pharmacy<br />
        <span style={{ color: "var(--text-2)" }}>{fmt(D.total_records)}</span> fills · {fmt(D.unique_patients)} patients<br />
        as of {D.as_of}
      </div>
    </nav>
  );
}
function TopNav({ view, setView }) {
  return (
    <div className="topnav">
      {NAV.map(n => (
        <button key={n.key} data-on={view === n.key ? "1" : "0"} onClick={() => setView(n.key)}>{n.label}</button>
      ))}
    </div>
  );
}

Object.assign(window, { useLS, useOutside, Card, KPI, Delta, Segmented, MonthRange, DateFilter, PayerSelect, ProductSelect, LineChips, PaperBillLens, Sidebar, TopNav, NAV, Unavail });
