// overlays.jsx — Correx overlays: command palette, approval gate, and inspectors.
const { useState, useEffect, useRef, useMemo } = React;

/* ── generic overlay shell ── */
function Overlay({ tag, title, esc = "esc", center, width, onClose, children }) {
  return (
    <div className={"scrim" + (center ? " center" : "")} onMouseDown={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="ovl" style={width ? { width } : null} onMouseDown={(e) => e.stopPropagation()}>
        <div className="ovl-h">
          <span className="tag">{tag}</span>
          <span className="ti">{title}</span>
          <span className="esc">{esc} to close</span>
        </div>
        <div className="ovl-b">{children}</div>
      </div>
    </div>
  );
}

/* ── command palette ── */
function CommandPalette({ commands, onRun, onClose }) {
  const [q, setQ] = useState("");
  const [i, setI] = useState(0);
  const inp = useRef(null);
  useEffect(() => { inp.current && inp.current.focus(); }, []);
  const score = (c) => {
    const s = (c.label + " " + c.hint).toLowerCase(), t = q.toLowerCase().trim();
    if (!t) return 1;
    if (s.includes(t)) return 2;
    let qi = 0; for (const ch of s) if (ch === t[qi]) qi++;
    return qi === t.length ? 1 : 0;
  };
  const list = useMemo(() => commands.map((c) => [c, score(c)]).filter(([, s]) => s > 0)
    .sort((a, b) => b[1] - a[1]).map(([c]) => c), [q]);
  useEffect(() => { setI(0); }, [q]);
  const key = (e) => {
    if (e.key === "ArrowDown") { setI((x) => Math.min(x + 1, list.length - 1)); e.preventDefault(); }
    else if (e.key === "ArrowUp") { setI((x) => Math.max(x - 1, 0)); e.preventDefault(); }
    else if (e.key === "Enter") { list[i] && onRun(list[i].id); e.preventDefault(); }
    else if (e.key === "Escape") { onClose(); }
    e.stopPropagation();
  };
  return (
    <div className="scrim" onMouseDown={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="ovl" style={{ width: "min(560px,94%)" }} onMouseDown={(e) => e.stopPropagation()}>
        <div className="cmd-input">
          <span className="pr">⌘</span>
          <input ref={inp} value={q} placeholder="Jump to a capability…" onChange={(e) => setQ(e.target.value)} onKeyDown={key} />
        </div>
        <div className="cmd-list">
          {list.length === 0 && <div className="hint-empty">no matches</div>}
          {list.map((c, n) => (
            <div key={c.id} className={"cmd-it" + (n === i ? " sel" : "")} onMouseEnter={() => setI(n)} onClick={() => onRun(c.id)}>
              <span className="ci-k">{c.key}</span>
              <span className="ci-l">{c.label}</span>
              <span className="ci-h">{c.hint}</span>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

/* ── approval gate (modal interrupt) ── */
function ApprovalModal({ data, onApprove, onReject, onSteer, onClose }) {
  const [steer, setSteer] = useState("");
  const sref = useRef(null);
  return (
    <div className="scrim center" onMouseDown={(e) => e.stopPropagation()}>
      <div className="ovl appr" onMouseDown={(e) => e.stopPropagation()}>
        <div className="appr-tier">
          <span className="appr-badge">{data.tier}</span>
          <div>
            <div className="lab">Approval required · <b>{data.tierLabel}</b></div>
            <div className="sub">{data.intent}</div>
          </div>
          <span className="esc" style={{ marginLeft: "auto" }}>execution paused</span>
        </div>
        <div className="ovl-b">
          <div className="appr-cmd"><span className="pr">$ </span>{data.command}</div>
          <div style={{ color: "var(--dim)", fontSize: 12.5, marginBottom: 6 }}>{data.detail}</div>
          <dl className="kv">
            <dt>tool</dt><dd>{data.tool} <span className="tag-tier tier-T3">{data.tier}</span></dd>
            <dt>reversible</dt><dd>{data.reversible ? "yes" : "no"}</dd>
            <dt>policy</dt><dd style={{ color: "var(--dim)" }}>{data.policy}</dd>
          </dl>
          <div style={{ margin: "10px 0 4px", color: "var(--dim)", fontSize: 11, letterSpacing: ".08em", textTransform: "uppercase" }}>semantic risk scan</div>
          {data.risks.map((r, n) => <div className="risk" key={n}>{r}</div>)}
          <div className="steer">
            <span style={{ color: "var(--accent)" }}>↳</span>
            <input ref={sref} value={steer} placeholder='steer + approve, e.g. "ok, but lock the version"'
              onChange={(e) => setSteer(e.target.value)}
              onKeyDown={(e) => { e.stopPropagation(); if (e.key === "Enter" && steer.trim()) onSteer(steer.trim()); if (e.key === "Escape") sref.current.blur(); }} />
          </div>
        </div>
        <div className="appr-acts">
          <button className="btn ok" onClick={() => onApprove(false)}>approve <kbd>a</kbd></button>
          <button className="btn ghost" onClick={() => onApprove(true)}>auto-approve session <kbd>A</kbd></button>
          <button className="btn" onClick={() => steer.trim() ? onSteer(steer.trim()) : sref.current.focus()}>steer <kbd>s</kbd></button>
          <button className="btn bad" onClick={onReject}>reject <kbd>r</kbd></button>
        </div>
      </div>
    </div>
  );
}

/* ── event stream inspector ── */
function EventInspector({ events, onClose }) {
  const cats = ["All", "Lifecycle", "Context", "Inference", "Tool", "Domain", "Approval"];
  const [cat, setCat] = useState("All");
  const [sel, setSel] = useState(events[events.length - 1]);
  const list = events.filter((e) => cat === "All" || e.cat === cat);
  const payload = {
    id: sel.id, type: sel.type, category: sel.cat, ts: "2026-05-29T" + sel.t,
    session_id: window.CORREX.SESSION.id, correlation_id: "cor-7f2a", causation_id: sel.id === "e49" ? "e48" : null,
    payload: { detail: sel.text },
  };
  return (
    <Overlay tag="events" title="Event stream inspector" onClose={onClose} width="min(820px,95%)">
      <div style={{ display: "flex", gap: 6, flexWrap: "wrap", marginBottom: 10 }}>
        {cats.map((c) => <span key={c} className={"pill" + (c === cat ? " live" : "")} style={{ cursor: "pointer" }} onClick={() => setCat(c)}>{c}</span>)}
      </div>
      <div style={{ display: "grid", gridTemplateColumns: "1.3fr 1fr", gap: 14 }}>
        <div>
          {list.map((e) => (
            <div key={e.id} className={"ev" + (e === sel ? " sel" : "")} onClick={() => setSel(e)}>
              <span className="ev-t">{e.t}</span>
              <span className={"ev-cat cat-" + e.cat}>{e.cat}</span>
              <span className="ev-tx"><b>{e.type}</b> {e.text}</span>
            </div>
          ))}
        </div>
        <div className="appr-cmd" style={{ margin: 0, alignSelf: "start", fontSize: 12 }}>
          <pre style={{ whiteSpace: "pre-wrap", margin: 0, color: "var(--fg)" }}>{JSON.stringify(payload, null, 2)}</pre>
        </div>
      </div>
    </Overlay>
  );
}

/* ── context pack inspector ── */
function ContextPackInspector({ pack, onClose }) {
  const pct = Math.round((pack.used / pack.budget) * 100);
  return (
    <Overlay tag="context" title="Context Pack — what the model receives" onClose={onClose} width="min(760px,95%)">
      <div style={{ display: "flex", alignItems: "center", gap: 12, marginBottom: 12 }}>
        <div style={{ color: "var(--fg-strong)", fontSize: 15 }}>{pack.used.toLocaleString()} <span style={{ color: "var(--dim)", fontSize: 12 }}>/ {pack.budget.toLocaleString()} tok</span></div>
        <div className="mono-bar" style={{ flex: 1 }}><i style={{ width: pct + "%" }} /></div>
        <div style={{ color: "var(--accent)" }}>{pct}%</div>
      </div>
      {pack.layers.map((l) => (
        <div className="row" key={l.id} style={{ gridTemplateColumns: "38px 150px 1fr 64px" }}>
          <span style={{ color: "var(--accent)", fontWeight: 600 }}>{l.id}</span>
          <span style={{ color: "var(--fg)" }}>{l.name}<br /><span style={{ color: "var(--faint)", fontSize: 11 }}>{l.mode}</span></span>
          <span style={{ color: "var(--dim)", fontSize: 12 }}>{l.items.join(" · ")}</span>
          <span style={{ color: "var(--dim)", textAlign: "right" }}>{l.tok}t</span>
        </div>
      ))}
      <div style={{ marginTop: 12, color: "var(--dim)", fontSize: 11, letterSpacing: ".08em", textTransform: "uppercase" }}>excluded by synthesis</div>
      {pack.dropped.map((d, n) => <div key={n} style={{ color: "var(--faint)", fontSize: 12.5, padding: "2px 0" }}>− {d}</div>)}
    </Overlay>
  );
}

/* ── stage / transition graph ── */
function StageGraph({ stages, transitions, onClose }) {
  const glyph = { done: "✔", active: "▸", pending: "·" };
  return (
    <Overlay tag="graph" title="Stage / transition graph" onClose={onClose} width="min(720px,95%)">
      <div style={{ display: "grid", gridTemplateColumns: "1.4fr 1fr", gap: 18 }}>
        <div>
          {stages.map((s, n) => (
            <div key={s.id}>
              <div style={{ display: "flex", alignItems: "baseline", gap: 10, padding: "5px 0" }}>
                <span style={{ width: 16, color: s.status === "active" ? "var(--accent)" : s.status === "done" ? "var(--ok)" : "var(--faint)" }}>{glyph[s.status]}</span>
                <span style={{ color: s.status === "pending" ? "var(--dim)" : "var(--fg-strong)", fontWeight: s.status === "active" ? 600 : 400, minWidth: 120 }}>{s.id}</span>
                <span style={{ color: "var(--faint)", fontSize: 11 }}>role:{s.role}</span>
                {s.status === "active" && <span className="pill live">running · {s.enter}</span>}
                <span style={{ color: "var(--dim)", fontSize: 12, marginLeft: "auto" }}>{s.note}</span>
              </div>
              {n < stages.length - 1 && <div style={{ marginLeft: 7, color: "var(--faint)", lineHeight: 1 }}>│</div>}
            </div>
          ))}
        </div>
        <div>
          <div style={{ color: "var(--dim)", fontSize: 11, letterSpacing: ".08em", textTransform: "uppercase", marginBottom: 8 }}>transition rules</div>
          <div style={{ color: "var(--faint)", fontSize: 11, marginBottom: 10 }}>no hardcoded graph — rules eval per artifact</div>
          {transitions.map((t, n) => (
            <div key={n} className="appr-cmd" style={{ margin: "0 0 8px", fontSize: 12 }}>
              <span style={{ color: "var(--accent-2)" }}>when</span> {t.when}<br />
              <span style={{ color: "var(--accent)" }}>→ goto</span> {t.goto}
            </div>
          ))}
        </div>
      </div>
    </Overlay>
  );
}

/* ── model registry / provider switch ── */
function ModelRegistry({ models, active, onSwitch, onClose }) {
  return (
    <Overlay tag="models" title="Model registry" onClose={onClose} width="min(800px,95%)">
      <div style={{ color: "var(--faint)", fontSize: 12, marginBottom: 8 }}>models are stateless engines — switching re-synthesizes the Context Pack for the new window.</div>
      {models.map((m) => (
        <div className={"row"} key={m.id} style={{ gridTemplateColumns: "1fr auto", cursor: m.id === active ? "default" : "pointer", opacity: m.status === "cold" ? 0.7 : 1 }} onClick={() => m.id !== active && onSwitch(m.id)}>
          <div>
            <div style={{ display: "flex", alignItems: "center", gap: 9 }}>
              <span style={{ color: m.id === active ? "var(--accent)" : "var(--fg-strong)", fontWeight: 600 }}>{m.id}</span>
              <span className={"pill " + (m.provider === "local" ? "live" : "")}>{m.provider}</span>
              {m.id === active && <span className="pill on">active</span>}
              <span className="pill off">{m.status}</span>
            </div>
            <div style={{ color: "var(--dim)", fontSize: 11.5, marginTop: 3 }}>{m.caps.join(" · ")} — ctx {m.ctx.toLocaleString()} · t={m.temp} · {m.gpu}</div>
          </div>
          <div style={{ textAlign: "right", color: "var(--faint)", fontSize: 11 }}>
            sessions {m.parallel}{m.id !== active && <div style={{ color: "var(--accent)" }}>switch →</div>}
          </div>
        </div>
      ))}
    </Overlay>
  );
}

/* ── tool palette ── */
function ToolPalette({ tools, onToggle, onClose }) {
  return (
    <Overlay tag="tools" title="Tool palette" onClose={onClose} width="min(720px,95%)">
      <div style={{ color: "var(--faint)", fontSize: 12, marginBottom: 8 }}>config-driven · capability-scoped. tier sets the approval gate; disabled tools are invisible to the agent.</div>
      {tools.map((t) => (
        <div className="row" key={t.id} style={{ gridTemplateColumns: "auto 1fr auto auto", cursor: "pointer", opacity: t.enabled ? 1 : 0.55 }} onClick={() => onToggle(t.id)}>
          <span className={"tag-tier tier-" + t.tier}>{t.tier}</span>
          <span><b style={{ color: "var(--fg-strong)", fontWeight: 600 }}>{t.id}</b> <span style={{ color: "var(--dim)", fontSize: 12 }}>— {t.desc}</span></span>
          <span className="pill" style={{ color: t.mode === "deny" ? "var(--bad)" : t.mode === "prompt" ? "var(--warn)" : "var(--ok)" }}>{t.mode}</span>
          <span className={"pill " + (t.enabled ? "on" : "off")}>{t.enabled ? "enabled" : "disabled"}</span>
        </div>
      ))}
    </Overlay>
  );
}

Object.assign(window, { Overlay, CommandPalette, ApprovalModal, EventInspector, ContextPackInspector, StageGraph, ModelRegistry, ToolPalette });
