// app.jsx — API-driven App for the Merger Control Navigator.
// Presentational components (StatsStrip, Filters, JurisdictionTable,
// RegionalMatrix, PartiesCard, DetailPanel, OverrideModal) are reused from
// dashboard.jsx / detail.jsx unchanged.

const { useState, useMemo, useEffect, useCallback, useRef } = React;
const { needsAttention } = window.MC_HELPERS;
const API = window.MC_API;
const CLERK = window.MC_CLERK;

function Login({ onOk }) {
  const [pw, setPw] = useState("");
  const [err, setErr] = useState(null);
  const submit = async () => {
    try { await API.login(pw); onOk(); }
    catch { setErr("Incorrect password."); }
  };
  return (
    <div className="login-wrap">
      <div className="card login-card">
        <div className="mark">MC</div>
        <h1>Merger Control Navigator</h1>
        <p>Internal test instance — enter the access password.</p>
        <input type="password" value={pw} placeholder="Password"
          onChange={(e) => setPw(e.target.value)}
          onKeyDown={(e) => e.key === "Enter" && submit()} />
        {err && <div className="hint err">{err}</div>}
        <button className="btn primary" onClick={submit}>Enter</button>
      </div>
    </div>
  );
}

// Clerk's mounted <SignIn> insists on routing its "Sign up" footer link to
// the hosted Account Portal (Clerk's signUpUrl prop is ignored in this
// instance's config). Workaround: hide Clerk's own footer, mount in
// "virtual" routing mode (no URL changes), and put our own React-state
// switch underneath. The two flows then share the same appearance and never
// touch Clerk's hosted pages.
const CLERK_APPEARANCE = {
  variables: {
    colorPrimary: "#6B176B",
    borderRadius: "10px",
    fontFamily: 'Inter, system-ui, -apple-system, "Segoe UI", sans-serif',
  },
  elements: {
    // Multiple keys for footer/dev-mode badge across Clerk versions —
    // setting all of them is the safe way to suppress them all.
    footer: { display: "none" },
    footerAction: { display: "none" },
    footerActionLink: { display: "none" },
    footerActionText: { display: "none" },
    developmentBadge: { display: "none" },
  },
};

function ClerkGate() {
  const ref = useRef(null);
  const [mode, setMode] = useState("signin"); // "signin" | "signup"

  useEffect(() => {
    if (!ref.current) return;
    const node = ref.current;
    const opts = { appearance: CLERK_APPEARANCE, routing: "virtual" };
    if (mode === "signup") CLERK.mountSignUp(node, opts);
    else CLERK.mountSignIn(node, opts);
    return () => {
      const c = CLERK.get();
      if (!c) return;
      if (mode === "signup") c.unmountSignUp(node);
      else c.unmountSignIn(node);
    };
  }, [mode]);

  return (
    <div className="clerk-gate">
      <div className="clerk-stack">
        <div ref={ref} className="clerk-mount" />
        <div className="auth-switch">
          {mode === "signin" ? (
            <>Don't have an account?{" "}
              <button className="link" onClick={() => setMode("signup")}>Sign up</button></>
          ) : (
            <>Already have an account?{" "}
              <button className="link" onClick={() => setMode("signin")}>Sign in</button></>
          )}
        </div>
      </div>
    </div>
  );
}

function ClerkUserButton() {
  const ref = useRef(null);
  useEffect(() => {
    if (ref.current) CLERK.mountUserButton(ref.current, { afterSignOutUrl: "/" });
  }, []);
  return <div ref={ref} className="clerk-userbtn" />;
}

const ROLE_OPTIONS = [
  ["", "Skip this sheet"],
  ["buyer", "Buyer"],
  ["target", "Target"],
  ["seller", "Seller"],
  ["jv_parent", "JV parent"],
  ["jv_entity", "JV entity"],
];

const CONFIDENCE_LABEL = { high: "High", medium: "Medium", low: "Low" };

function MappingReviewModal({ proposal, file, onClose, onConfirmed }) {
  const [mapping, setMapping] = useState(proposal);
  const [name, setName] = useState(file.name.replace(/\.xlsx$/i, ""));
  const [busy, setBusy] = useState(false);
  const [err, setErr] = useState(null);

  const updateSheet = (idx, patch) => setMapping((m) => ({
    ...m,
    sheets: m.sheets.map((s, i) => i === idx ? { ...s, ...patch } : s),
  }));
  const updateRoot = (patch) => setMapping((m) => ({ ...m, ...patch }));

  const isJv = mapping.transaction_type === "jv_creation";
  const partyRows = mapping.sheets.filter((s) => s.role);
  const skipRows = mapping.sheets.filter((s) => !s.role);

  const confirm = async () => {
    if (!name.trim()) { setErr("Matter name is required."); return; }
    if (!partyRows.length) { setErr("At least one sheet must be assigned a party role."); return; }
    setBusy(true); setErr(null);
    try {
      const matter = await API.createFromMapping({ file, name, mapping });
      await onConfirmed(matter);
    } catch (e) {
      console.error("createFromMapping failed", e);
      setErr(e && e.unauthorized
        ? "Session expired — please sign in again."
        : (e && e.message) ? e.message : "Request failed");
    } finally { setBusy(false); }
  };

  return (
    <div className="modal-backdrop" onClick={busy ? undefined : onClose}>
      <div className="modal mapping-modal" onClick={(e) => e.stopPropagation()}>
        <div className="hd">
          <h2>Review mapping</h2>
          <div className="sub">
            The AI inferred the structure of <b>{file.name}</b>. Adjust anything
            that looks wrong before screening runs.
            <span className="conf-chip" data-conf={mapping.confidence}>
              AI confidence: {CONFIDENCE_LABEL[mapping.confidence] || mapping.confidence}
            </span>
          </div>
        </div>
        <div className="bd mapping-body">
          <div className="field">
            <label>Matter name</label>
            <input type="text" value={name} onChange={(e) => setName(e.target.value)}
              placeholder="e.g. Project Botticelli" />
          </div>

          <div className="mapping-row">
            <div className="field">
              <label>Transaction type</label>
              <select value={mapping.transaction_type}
                onChange={(e) => updateRoot({ transaction_type: e.target.value })}>
                {TXN_OPTIONS.map(([v, l]) => <option key={v} value={v}>{l}</option>)}
              </select>
            </div>
            <div className="field">
              <label>Reporting year</label>
              <input type="number" value={mapping.reporting_year}
                onChange={(e) => updateRoot({ reporting_year: +e.target.value })} />
            </div>
          </div>

          {isJv && (
            <div className="mapping-row">
              <div className="field">
                <label>Greenfield / brownfield</label>
                <select value={mapping.jv_greenfield_or_brownfield || "greenfield"}
                  onChange={(e) => updateRoot({ jv_greenfield_or_brownfield: e.target.value })}>
                  <option value="greenfield">Greenfield</option>
                  <option value="brownfield">Brownfield</option>
                </select>
              </div>
              <div className="field chk-inline">
                <label>
                  <input type="checkbox" checked={!!mapping.jv_full_function}
                    onChange={(e) => updateRoot({ jv_full_function: e.target.checked })} />
                  <span>Full-function JV</span>
                </label>
              </div>
            </div>
          )}

          <div className="field">
            <label>Control structure (lawyer-readable)</label>
            <textarea rows={2} value={mapping.control_structure_description}
              onChange={(e) => updateRoot({ control_structure_description: e.target.value })} />
          </div>

          <div className="mapping-section">
            <div className="section-label">Sheets identified as parties</div>
            {partyRows.length === 0 && (
              <div className="hint">No sheet was assigned a party role. Use the role dropdowns below to add one.</div>
            )}
            {mapping.sheets.map((s, i) => s.role && (
              <div key={s.sheet_name + i} className="sheet-row">
                <div className="sheet-hd">
                  <span className="sheet-name">"{s.sheet_name}"</span>
                  <span className="sheet-cols">
                    Country col {s.country_col} · Amount col {s.amount_col} · Header row {s.header_row}
                  </span>
                </div>
                <div className="sheet-fields">
                  <label>
                    <span>Role</span>
                    <select value={s.role || ""} onChange={(e) => updateSheet(i, { role: e.target.value || null })}>
                      {ROLE_OPTIONS.map(([v, l]) => <option key={v} value={v}>{l}</option>)}
                    </select>
                  </label>
                  <label>
                    <span>Party name</span>
                    <input value={s.party_name} onChange={(e) => updateSheet(i, { party_name: e.target.value })} />
                  </label>
                  <label>
                    <span>Currency</span>
                    <input value={s.currency} onChange={(e) => updateSheet(i, { currency: e.target.value.toUpperCase() })}
                      maxLength={3} />
                  </label>
                </div>
                {s.skip_labels && s.skip_labels.length > 0 && (
                  <div className="sheet-skip">Skipping aggregates: {s.skip_labels.join(", ")}</div>
                )}
                {s.notes && <div className="sheet-notes">AI note: {s.notes}</div>}
              </div>
            ))}
          </div>

          {skipRows.length > 0 && (
            <div className="mapping-section">
              <div className="section-label">Sheets being skipped</div>
              {skipRows.map((s, i) => (
                <div key={s.sheet_name + "skip" + i} className="sheet-row skipped">
                  <div className="sheet-hd">
                    <span className="sheet-name">"{s.sheet_name}"</span>
                    <select value="" onChange={(e) => {
                      const idx = mapping.sheets.indexOf(s);
                      updateSheet(idx, { role: e.target.value || null });
                    }}>
                      {ROLE_OPTIONS.map(([v, l]) => <option key={v} value={v}>{l}</option>)}
                    </select>
                  </div>
                  {s.notes && <div className="sheet-notes">AI note: {s.notes}</div>}
                </div>
              ))}
            </div>
          )}

          {mapping.proposal_notes && (
            <div className="ai-commentary">
              <div className="section-label">AI commentary</div>
              <p>{mapping.proposal_notes}</p>
            </div>
          )}

          {err && <div className="status-strip err">{err}</div>}
        </div>
        <div className="ft">
          <button className="btn ghost" onClick={onClose} disabled={busy}>Cancel</button>
          <button className="btn primary" onClick={confirm} disabled={busy}>
            {busy ? "Creating matter…" : "Confirm & screen →"}
          </button>
        </div>
      </div>
    </div>
  );
}

const TXN_OPTIONS = [
  ["sole_control_acquisition", "Sole-control acquisition"],
  ["joint_control_acquisition", "Joint-control acquisition"],
  ["merger", "Merger"],
  ["jv_creation", "Joint-venture creation"],
  ["minority_acquisition", "Minority acquisition"],
];
// Intake adapters map a specific spreadsheet layout onto the engine's Case
// model. Each "format" below is a hand-coded adapter for one observed deal-
// team workbook convention; arbitrary spreadsheets need a new adapter (or
// a future generic / LLM-driven intake — see TODO note).
const INTAKE_OPTIONS = [
  ["botticelli", "Botticelli layout — 2-party deal, EUR per sheet"],
  ["runway", "Runway layout — 3-parent JV, USD per sheet"],
];

function SampleTile({ tag, title, sub, body, onClick, busy }) {
  return (
    <button className="sample-tile" disabled={busy} onClick={onClick}>
      <span className="tag">{tag}</span>
      <span className="title">{title}</span>
      <span className="sub">{sub}</span>
      <span className="body">{body}</span>
      <span className="cta">Run sample →</span>
    </button>
  );
}

function NewMatter({ onCreated }) {
  const [busy, setBusy] = useState(false);
  const [err, setErr] = useState(null);
  const [name, setName] = useState("");
  const [intake, setIntake] = useState("botticelli");
  const [txn, setTxn] = useState("sole_control_acquisition");
  const [year, setYear] = useState(2021);
  const [ff, setFf] = useState(false);
  const [gb, setGb] = useState("greenfield");
  const [file, setFile] = useState(null);
  const fileInputRef = useRef(null);

  // Auto-detect (generic intake) state
  const [autoFile, setAutoFile] = useState(null);
  const [autoBusy, setAutoBusy] = useState(false);
  const [autoErr, setAutoErr] = useState(null);
  const [proposal, setProposal] = useState(null); // {mapping, filename}
  const autoFileRef = useRef(null);

  const runAutoDetect = async (chosen) => {
    setAutoBusy(true); setAutoErr(null); setProposal(null);
    setAutoFile(chosen);
    try {
      const r = await API.proposeMapping(chosen);
      setProposal(r);
    } catch (e) {
      console.error("proposeMapping failed", e);
      setAutoErr(e && e.unauthorized
        ? "Session expired — please sign in again."
        : (e && e.message) ? `Auto-detect failed: ${e.message}` : "Auto-detect failed");
    } finally { setAutoBusy(false); }
  };
  const cancelProposal = () => { setProposal(null); setAutoFile(null); };

  const reportErr = (label, e) => {
    console.error(label, e);
    if (e && e.unauthorized) setErr("Session expired or unauthorized — please sign in again.");
    else setErr((e && e.message) ? `${label}: ${e.message}` : `${label}: request failed`);
  };
  const sample = async (which) => {
    setBusy(true); setErr(null);
    try { await onCreated(await API.quickSample(which)); }
    catch (e) { reportErr("Sample failed", e); } finally { setBusy(false); }
  };
  const create = async () => {
    if (!name.trim() || !file) { setErr("A matter name and a spreadsheet are both required."); return; }
    setBusy(true); setErr(null);
    const fd = new FormData();
    fd.append("name", name); fd.append("intake", intake);
    fd.append("transaction_type", txn); fd.append("reporting_year", year);
    fd.append("params", JSON.stringify(
      txn === "jv_creation" ? { full_function: ff, greenfield_or_brownfield: gb } : {}));
    fd.append("files", file);
    try { await onCreated(await API.createMatter(fd)); }
    catch (e) { reportErr("Create failed", e); } finally { setBusy(false); }
  };

  return (
    <div className="newmatter">
      <header className="newmatter-header">
        <h1>New matter</h1>
        <p>
          Start with a synthetic sample to explore the tool end-to-end, or
          upload a turnover spreadsheet to screen a real deal across 211
          jurisdictions.
        </p>
      </header>

      <section className="card sample-card">
        <div className="card-hd">
          Quick start — synthetic samples
          <span className="card-hd-sub">no client data</span>
        </div>
        <div className="sample-grid">
          <SampleTile
            tag="Acquisition"
            title="Sole-control acquisition"
            sub="Multi-jurisdictional, ~€1.4 bn worldwide"
            body="Fabricated US-headquartered acquirer taking sole control of a European target. Tests turnover screening, deterministic exclusions, and full LLM assessment across required, borderline and info-needed outcomes."
            onClick={() => sample("acquisition")}
            busy={busy}
          />
          <SampleTile
            tag="JV creation"
            title="Three-parent joint venture"
            sub="Non-full-function, greenfield"
            body="Three-parent JV (EU + APAC) with greenfield deployment. Exercises the JV gate, the greenfield/brownfield branch, and supranational regime resolution (EU, COMESA)."
            onClick={() => sample("jv")}
            busy={busy}
          />
        </div>
        {busy && <div className="status-strip working">Creating matter and running screening…</div>}
      </section>

      <section className="card autodetect-card">
        <div className="card-hd">
          Upload any spreadsheet
          <span className="card-hd-sub">AI infers structure, you confirm</span>
        </div>
        <div className="autodetect-body">
          <p className="autodetect-lede">
            Upload a turnover spreadsheet in any layout — sheets per party,
            country and amount columns wherever they sit. Claude reads the
            workbook structure and proposes a mapping; you review and adjust
            before screening runs.
          </p>
          <input ref={autoFileRef} type="file" accept=".xlsx"
            style={{ display: "none" }}
            onChange={(e) => { const f = e.target.files[0]; if (f) runAutoDetect(f); }} />
          <button type="button" className="file-cta"
            disabled={autoBusy}
            onClick={() => autoFileRef.current && autoFileRef.current.click()}>
            <span className="paperclip">✨</span>
            <span className="file-text">
              {autoBusy ? "Reading workbook…"
                : autoFile ? autoFile.name
                : "Choose an .xlsx to auto-detect"}
            </span>
            <span className="file-hint">
              {autoBusy ? "Claude is inferring the mapping"
                : "Any layout — review next"}
            </span>
          </button>
          {autoErr && <div className="status-strip err">{autoErr}</div>}
        </div>
      </section>

      <section className="card create-card">
        <div className="card-hd">
          Use a fixed adapter
          <span className="card-hd-sub">deterministic — only for known layouts</span>
        </div>
        <div className="form-grid">
          <label className="field-block field-span-2">
            <span className="lbl">Matter name</span>
            <input value={name} onChange={(e) => setName(e.target.value)}
              placeholder="e.g. Project Botticelli" />
          </label>

          <label className="field-block">
            <span className="lbl">Transaction type</span>
            <select value={txn} onChange={(e) => setTxn(e.target.value)}>
              {TXN_OPTIONS.map(([v, l]) => <option key={v} value={v}>{l}</option>)}
            </select>
          </label>

          <label className="field-block">
            <span className="lbl">Reporting year</span>
            <input type="number" value={year} onChange={(e) => setYear(+e.target.value)} />
          </label>

          <label className="field-block field-span-2">
            <span className="lbl">Source layout</span>
            <select value={intake} onChange={(e) => setIntake(e.target.value)}>
              {INTAKE_OPTIONS.map(([v, l]) => <option key={v} value={v}>{l}</option>)}
            </select>
            <span className="field-help">
              Pick the layout that matches your spreadsheet's column and sheet
              structure — not the deal type. Today each layout is a hand-coded
              adapter; arbitrary spreadsheets need a new one. A generic intake
              that auto-maps any workbook is on the roadmap.
            </span>
          </label>

          {txn === "jv_creation" && (
            <label className="field-block">
              <span className="lbl">Greenfield / brownfield</span>
              <select value={gb} onChange={(e) => setGb(e.target.value)}>
                <option value="greenfield">Greenfield</option>
                <option value="brownfield">Brownfield</option>
              </select>
            </label>
          )}

          {txn === "jv_creation" && (
            <label className="field-block field-span-2 chk">
              <input type="checkbox" checked={ff}
                onChange={(e) => setFf(e.target.checked)} />
              <span>Full-function JV (autonomous economic entity)</span>
            </label>
          )}

          <div className="field-block field-span-2 file-drop">
            <span className="lbl">Spreadsheet</span>
            <input
              ref={fileInputRef}
              type="file" accept=".xlsx"
              onChange={(e) => setFile(e.target.files[0])} />
            <button type="button" className="file-cta"
              onClick={() => fileInputRef.current && fileInputRef.current.click()}>
              <span className="paperclip">📎</span>
              <span className="file-text">
                {file ? file.name : "Choose an .xlsx file"}
              </span>
              <span className="file-hint">
                {file ? "Click to change" : "Botticelli or Runway format"}
              </span>
            </button>
          </div>
        </div>

        {err && <div className="status-strip err">{err}</div>}

        <div className="form-actions">
          <button className="btn primary" disabled={busy} onClick={create}>
            {busy ? "Working…" : "Create & screen →"}
          </button>
          <span className="form-hint">
            Screening is deterministic and instant — LLM assessment is a
            separate, opt-in step on the matter dashboard.
          </span>
        </div>
      </section>

      {proposal && autoFile && (
        <MappingReviewModal
          proposal={proposal.mapping}
          file={autoFile}
          onClose={cancelProposal}
          onConfirmed={async (matter) => { cancelProposal(); await onCreated(matter); }}
        />
      )}
    </div>
  );
}

function AuditDrawer({ audit, onClose }) {
  return (
    <div className="modal-backdrop" onClick={onClose}>
      <div className="modal audit-modal" onClick={(e) => e.stopPropagation()}>
        <div className="hd"><h2>Audit trail</h2></div>
        <div className="bd">
          {!audit.length ? <div className="muted">No lawyer edits yet.</div> : (
            <table className="audit-table">
              <thead><tr><th>When</th><th>Who</th><th>Jurisdiction</th><th>Field</th><th>From</th><th>To</th></tr></thead>
              <tbody>{audit.map((a, i) => (
                <tr key={i}><td>{a.at}</td><td>{a.who}</td><td>{a.jurisdiction}</td>
                  <td>{a.field}</td><td>{a.old_value}</td><td>{a.new_value}</td></tr>
              ))}</tbody>
            </table>
          )}
        </div>
        <div className="ft"><button className="btn ghost" onClick={onClose}>Close</button></div>
      </div>
    </div>
  );
}

function PartiesDrawer({ matter, onClose }) {
  return (
    <div className="modal-backdrop" onClick={onClose}>
      <div className="modal parties-modal" onClick={(e) => e.stopPropagation()}>
        <div className="hd">
          <h2>Deal parties &amp; turnover</h2>
          <div className="sub">
            Fixed deal inputs — {matter.transactionType} · {matter.client} · FY{matter.reportingYear}
          </div>
        </div>
        <div className="bd nopad">
          <PartiesCard matter={matter} />
        </div>
        <div className="ft"><button className="btn ghost" onClick={onClose}>Close</button></div>
      </div>
    </div>
  );
}

function App() {
  const [phase, setPhase] = useState("loading"); // loading | login | clerk | ready
  const [authMode, setAuthMode] = useState("none"); // none | password | clerk
  const [regions, setRegions] = useState([]);
  const [matters, setMatters] = useState([]);
  const [currentId, setCurrentId] = useState(null); // null = New-matter view
  const [data, setData] = useState(null); // {matter, rows, audit}
  const [filters, setFilters] = useState({ search: "", outcomes: [], attnOnly: false, overOnly: false });
  const [sort, setSort] = useState({ key: "outcome", dir: "asc" });
  const [selectedIso, setSelectedIso] = useState(null);
  const [overrideOpen, setOverrideOpen] = useState(false);
  const [auditOpen, setAuditOpen] = useState(false);
  const [partiesOpen, setPartiesOpen] = useState(false);

  const loadBootstrap = useCallback(async () => {
    const b = await API.bootstrap();
    setRegions(b.regions); setMatters(b.matters);
    return b.matters;
  }, []);

  const bootedRef = useRef(false);
  const enterApp = useCallback(async () => {
    const ms = await loadBootstrap();
    if (ms.length) setCurrentId(ms[0].id);
    setPhase("ready");
  }, [loadBootstrap]);

  useEffect(() => {
    (async () => {
      let mode = "none";
      try {
        const cfg = await API.config();
        mode = cfg.authMode;
        setAuthMode(cfg.authMode);

        if (cfg.authMode === "clerk") {
          await CLERK.ensure(cfg.clerkPublishableKey);
          API.setTokenGetter(CLERK.getToken);
          const sync = async () => {
            if (CLERK.user()) {
              if (bootedRef.current) return;
              bootedRef.current = true;
              await enterApp();
            } else {
              bootedRef.current = false;
              setPhase("clerk");
            }
          };
          CLERK.onChange(() => { sync().catch(() => {}); });
          await sync();
          return;
        }

        if (cfg.authMode === "password") {
          const s = await API.authStatus();
          if (!s.authed) { setPhase("login"); return; }
        }
        await enterApp();
      } catch (e) {
        if (e && e.unauthorized) setPhase(mode === "clerk" ? "clerk" : "login");
        else setPhase("ready");
      }
    })();
  }, [enterApp]);

  const loadMatter = useCallback(async (id) => {
    const d = await API.matter(id);
    setData(d);
    setSelectedIso(d.rows[0]?.iso || null);
    setFilters({ search: "", outcomes: [], attnOnly: false, overOnly: false });
  }, []);

  useEffect(() => { if (currentId) loadMatter(currentId); else setData(null); }, [currentId, loadMatter]);

  // Poll while an assessment is running
  useEffect(() => {
    if (!data || data.matter.status !== "assessing") return;
    const t = setInterval(() => loadMatter(currentId), 3000);
    return () => clearInterval(t);
  }, [data, currentId, loadMatter]);

  if (phase === "loading") return <div className="splash">Loading…</div>;
  if (phase === "clerk") return <ClerkGate />;
  if (phase === "login") return <Login onOk={async () => {
    const ms = await loadBootstrap(); if (ms.length) setCurrentId(ms[0].id); setPhase("ready");
  }} />;

  const rows = data?.rows || [];
  const matter = data?.matter || null;
  const assessing = matter && matter.status === "assessing";
  const prog = assessing ? (matter.progress || null) : null;
  const progPct = prog && prog.total ? Math.round((prog.done / prog.total) * 100) : null;

  const counts = {};
  rows.forEach((r) => { const e = r.lawyerOutcome || r.outcome; counts[e] = (counts[e] || 0) + 1; });
  const attnCount = rows.filter(needsAttention).length;

  const visibleRows = (() => {
    let out = rows.slice();
    if (!filters.outcomes.includes("excluded")) out = out.filter((r) => r.outcome !== "excluded");
    if (filters.outcomes.length) out = out.filter((r) => filters.outcomes.includes(r.lawyerOutcome || r.outcome));
    if (filters.attnOnly) out = out.filter(needsAttention);
    if (filters.overOnly) out = out.filter((r) => r.overridden);
    if (filters.search.trim()) {
      const s = filters.search.trim().toLowerCase();
      out = out.filter((r) => r.name.toLowerCase().includes(s) || r.iso.toLowerCase().includes(s));
    }
    const order = { required: 0, borderline: 1, info_needed: 2, not_required: 3, excluded: 4 };
    out.sort((a, b) => {
      let av, bv;
      if (sort.key === "outcome") { av = order[a.lawyerOutcome || a.outcome]; bv = order[b.lawyerOutcome || b.outcome]; }
      else if (sort.key === "toolOutcome") { av = order[a.toolOutcome]; bv = order[b.toolOutcome]; }
      else if (sort.key === "confidence") { const o = { high: 0, medium: 1, low: 2 }; av = o[a.confidence] ?? 3; bv = o[b.confidence] ?? 3; }
      else if (sort.key === "flags") {
        av = -((a.approved ? 10 : 0) + (a.overridden ? 5 : 0) + (needsAttention(a) ? 1 : 0));
        bv = -((b.approved ? 10 : 0) + (b.overridden ? 5 : 0) + (needsAttention(b) ? 1 : 0));
      } else { av = a[sort.key]; bv = b[sort.key]; }
      if (av < bv) return sort.dir === "asc" ? -1 : 1;
      if (av > bv) return sort.dir === "asc" ? 1 : -1;
      return a.name.localeCompare(b.name);
    });
    return out;
  })();

  const selectedRec = rows.find((r) => r.iso === selectedIso) || null;
  const screenedOut = filters.outcomes.includes("excluded") ? 0 : rows.filter((r) => r.outcome === "excluded").length;

  const doOverride = async (patch) => {
    const d = await API.override(currentId, {
      jurisdiction: selectedRec.name,
      lawyerOutcome: patch.lawyerOutcome,
      lawyerNote: patch.lawyerNote,
      approved: patch.approved !== undefined ? patch.approved : selectedRec.approved,
      who: matter.associate && matter.associate !== "—" ? matter.associate : "lawyer",
    });
    setData((p) => ({ ...p, rows: d.rows, audit: d.audit }));
    setOverrideOpen(false);
  };
  const doApprove = async (v) => {
    const d = await API.override(currentId, {
      jurisdiction: selectedRec.name, lawyerOutcome: selectedRec.lawyerOutcome,
      lawyerNote: selectedRec.lawyerNote, approved: v,
      who: matter.associate && matter.associate !== "—" ? matter.associate : "lawyer",
    });
    setData((p) => ({ ...p, rows: d.rows, audit: d.audit }));
  };
  const doRun = async () => {
    try { await API.run(currentId); await loadMatter(currentId); }
    catch (e) { alert(e.message || "Run failed"); }
  };
  const onCreated = async (m) => { await loadBootstrap(); setCurrentId(m.id); };

  return (
    <div className="app">
      <div className="topbar">
        <div className="brand"><span className="mark">MC</span><span>Merger Control Navigator</span></div>
        <div className="matter-switch" role="tablist">
          {matters.map((m) => (
            <button key={m.id} className={m.id === currentId ? "active" : ""}
              onClick={() => setCurrentId(m.id)}>{m.name}</button>
          ))}
        </div>
        <div className="right">
          <button className="btn ghost" onClick={() => setCurrentId(null)}>+ New</button>
          {authMode === "clerk" && <ClerkUserButton />}
        </div>
      </div>

      {currentId === null || !matter ? (
        <NewMatter onCreated={onCreated} />
      ) : (
        <>
          <div className="matter-header">
            <div className="title-block">
              <h1>{matter.name}</h1>
              <div className="meta">
                <span><b style={{ color: "var(--fg)", fontWeight: 600 }}>{matter.transactionType}</b></span>
                <span className="dot">·</span><span>{matter.client}</span>
                <span className="dot">·</span><span>FY{matter.reportingYear}</span>
                <span className="dot">·</span><span>Combined turnover {matter.combinedWorldwide}</span>
                <span className="dot">·</span>
                <span className={`pill ${assessing ? "pill-live" : ""}`}>
                  {assessing && prog
                    ? `Assessing… ${prog.done} / ${prog.total || "…"}`
                    : matter.statusLabel}
                </span>
                {matter.partner && matter.partner !== "—" && <span className="pill">Partner: {matter.partner}</span>}
              </div>
              {assessing && (
                <div className="assess-progress" role="progressbar"
                  aria-valuenow={progPct ?? undefined} aria-valuemin={0} aria-valuemax={100}>
                  <div className={`track ${progPct == null ? "indet" : ""}`}>
                    <div className="bar" style={progPct != null ? { width: progPct + "%" } : undefined} />
                  </div>
                  <span className="lbl">
                    {prog && prog.total
                      ? `${progPct}% — ${prog.done} of ${prog.total} jurisdictions assessed · table updates live`
                      : "Starting LLM assessment…"}
                  </span>
                </div>
              )}
            </div>
            <div className="actions">
              <button className="btn ghost" onClick={() => setPartiesOpen(true)}>Deal parties</button>
              <button className="btn ghost" onClick={() => setAuditOpen(true)}>Audit trail</button>
              <button className="btn" onClick={doRun} disabled={assessing}>
                {assessing
                  ? (prog ? `Assessing ${prog.done}/${prog.total || "…"}` : "Assessing…")
                  : "▶ Run assessment"}
              </button>
              <button className="btn primary" onClick={async () => {
                try { await API.downloadExport(currentId, matter.name); }
                catch (e) { alert(e && e.unauthorized ? "Session expired — please sign in again." : "Export failed"); }
              }}>⬇ Export Excel</button>
            </div>
          </div>

          <StatsStrip counts={counts} total={rows.length} attnCount={attnCount} />

          <div className="overview-band">
            <RegionalMatrix rows={rows} regions={regions}
              selectedIso={selectedIso} onSelect={setSelectedIso} />
          </div>

          <div className="main">
            <div className="left-col">
              <div className="card">
                <Filters filters={filters} setFilters={setFilters} counts={counts}
                  total={rows.length} shown={visibleRows.length} />
              </div>
              <JurisdictionTable rows={visibleRows} sort={sort} setSort={setSort}
                selectedIso={selectedIso} onSelect={setSelectedIso}
                screenedOutCount={screenedOut}
                onClearFilters={() => setFilters({ search: "", outcomes: [], attnOnly: false, overOnly: false })} />
            </div>
            <div className="right-col">
              <DetailPanel rec={selectedRec} matter={matter}
                onOpenOverride={() => setOverrideOpen(true)} onApprove={doApprove} />
            </div>
          </div>

          {overrideOpen && selectedRec && (
            <OverrideModal rec={selectedRec} onClose={() => setOverrideOpen(false)} onSave={doOverride} />
          )}
          {auditOpen && <AuditDrawer audit={data.audit || []} onClose={() => setAuditOpen(false)} />}
          {partiesOpen && <PartiesDrawer matter={matter} onClose={() => setPartiesOpen(false)} />}
        </>
      )}
    </div>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
