/* Integrations catalog · Audit engagement room · Analytics (cost + latency) · Risk register */

/* ============================================================
   Integrations catalog
   ============================================================ */

const INTEGRATIONS = [
  { id: "slack", name: "Slack", category: "Alerting", desc: "Post verification failures + share-link openings into a channel.", installed: true, events: 3 },
  { id: "pagerduty", name: "PagerDuty", category: "Alerting", desc: "Page on-call when a contradicted claim hits production.", installed: true, events: 1 },
  { id: "datadog", name: "Datadog", category: "Observability", desc: "Forward Attestia metrics + spans into your existing dashboards.", installed: false },
  { id: "splunk", name: "Splunk", category: "SIEM", desc: "Stream the evidence chain into your enterprise SIEM.", installed: false },
  { id: "okta", name: "Okta", category: "SSO", desc: "SAML SSO + SCIM provisioning for tenants.", installed: true, events: 0 },
  { id: "azureAD", name: "Microsoft Entra ID", category: "SSO", desc: "SAML SSO + SCIM provisioning for tenants.", installed: false },
  { id: "jira", name: "Jira", category: "Issue tracking", desc: "Auto-file tickets for contradicted claims, assigned to the app owner.", installed: false },
  { id: "linear", name: "Linear", category: "Issue tracking", desc: "Same as Jira, for Linear-using teams.", installed: false },
  { id: "snowflake", name: "Snowflake", category: "Data warehouse", desc: "Daily export of the evidence chain + per-claim verdicts.", installed: true, events: 1 },
  { id: "bigquery", name: "BigQuery", category: "Data warehouse", desc: "Same as Snowflake, BigQuery-native.", installed: false },
  { id: "github", name: "GitHub", category: "CI", desc: "Source code scanning to detect un-wrapped LLM calls. Required for bulletin.", installed: true, events: 0 },
  { id: "openai", name: "OpenAI", category: "LLM provider", desc: "Wrap OpenAI client. Required for first call.", installed: true, events: 0 },
  { id: "anthropic", name: "Anthropic", category: "LLM provider", desc: "Wrap Anthropic client.", installed: false },
  { id: "gemini", name: "Google Gemini", category: "LLM provider", desc: "Wrap Gemini client.", installed: false },
  { id: "bedrock", name: "AWS Bedrock", category: "LLM provider", desc: "Wrap Bedrock client.", installed: false },
  { id: "epic", name: "Epic FHIR", category: "Healthcare", desc: "Pull patient context for grounding. PHI never leaves redaction.", installed: false },
];

const INTEG_CATEGORIES = ["All", "Alerting", "Observability", "SIEM", "SSO", "Issue tracking", "Data warehouse", "CI", "LLM provider", "Healthcare"];

const IntegrationsPage = ({ pushToast }) => {
  const [cat, setCat] = React.useState("All");
  const [search, setSearch] = React.useState("");
  const [openInt, setOpenInt] = React.useState(null);

  const filtered = INTEGRATIONS.filter((i) =>
    (cat === "All" || i.category === cat) &&
    (!search || i.name.toLowerCase().includes(search.toLowerCase()))
  );

  return (
    <>
      <header className="page-header">
        <div className="page-header__inner">
          <div className="page-header__eyebrow">Workspace</div>
          <h1>Integrations</h1>
          <p className="page-header__sub">
            Connect Attestia to the rest of your stack — alerting, SIEM, data warehouse, SSO, issue tracking. {INTEGRATIONS.filter(i => i.installed).length} of {INTEGRATIONS.length} installed.
          </p>
        </div>
        <div className="page-actions">
          <Button variant="secondary" size="sm" icon={window.Icon.external({ size: 12 })}>Request integration</Button>
        </div>
      </header>

      <div className="toolbar" style={{ marginBottom: "var(--space-4)" }}>
        <div className="search-input" style={{ minWidth: 320 }}>
          {window.Icon.search({ size: 14 })}
          <input placeholder="Search integrations…" value={search} onChange={(e) => setSearch(e.target.value)} />
        </div>
        <div className="spacer" />
        <span className="text-xs muted">{filtered.length} shown</span>
      </div>

      <div className="cat-row">
        {INTEG_CATEGORIES.map((c) => (
          <button key={c} className={`cat-chip ${cat === c ? "cat-chip--active" : ""}`} onClick={() => setCat(c)}>
            {c}
            <span className="cat-chip__count mono">
              {c === "All" ? INTEGRATIONS.length : INTEGRATIONS.filter((i) => i.category === c).length}
            </span>
          </button>
        ))}
      </div>

      <div className="integ-grid">
        {filtered.map((i) => (
          <button key={i.id} className="integ-card" onClick={() => setOpenInt(i)}>
            <div className="integ-card__icon">
              <IntegLogo name={i.name} />
            </div>
            <div className="integ-card__body">
              <div className="integ-card__head">
                <span className="fw-600 text-md">{i.name}</span>
                {i.installed && <Badge tone="sealed" icon={window.Icon.checkSimple({ size: 10 })}>Installed</Badge>}
              </div>
              <div className="integ-card__cat mono text-xs">{i.category.toUpperCase()}</div>
              <div className="integ-card__desc">{i.desc}</div>
            </div>
            {i.installed
              ? <Button variant="ghost" size="sm">Configure</Button>
              : <Button variant="secondary" size="sm" icon={window.Icon.plus({ size: 12 })}>Install</Button>}
          </button>
        ))}
      </div>

      <Modal open={!!openInt} onClose={() => setOpenInt(null)} wide
        title={openInt?.installed ? `Configure ${openInt?.name}` : `Install ${openInt?.name}`}
        sub={openInt?.desc}
        footer={
          <>
            <Button variant="ghost" onClick={() => setOpenInt(null)}>Cancel</Button>
            {openInt?.installed
              ? <Button variant="destructive" onClick={() => { setOpenInt(null); pushToast({ kind: "warn", title: `${openInt?.name} disconnected` }); }}>Disconnect</Button>
              : <Button variant="primary" onClick={() => { setOpenInt(null); pushToast({ kind: "success", title: `${openInt?.name} installed` }); }} icon={window.Icon.plus({ size: 13 })}>Authorize &amp; install</Button>}
          </>
        }
      >
        {openInt && (
          <div className="col gap-4">
            <Field label="Events to subscribe to">
              <div className="col gap-2">
                {["verification.failed", "evidence.signed", "share.created", "contradicted.claim", "sandbox.unhealthy"].map((ev) => (
                  <label key={ev} className="row gap-2" style={{ padding: 8, border: "1px solid var(--rule)", borderRadius: "var(--radius-md)" }}>
                    <input type="checkbox" defaultChecked={["verification.failed", "evidence.signed"].includes(ev)} />
                    <span className="mono text-sm" style={{ flex: 1 }}>{ev}</span>
                    <span className="text-xs muted">{Math.round(Math.random() * 200)} events/wk</span>
                  </label>
                ))}
              </div>
            </Field>
            {openInt.installed && (
              <Field label="Connected since">
                <div className="text-sm">Apr 18, 2026 · by Mike Chen</div>
              </Field>
            )}
          </div>
        )}
      </Modal>
    </>
  );
};

const IntegLogo = ({ name }) => {
  // Minimal monogram-style logo so we don't depend on brand assets.
  const initials = name.split(" ").map((w) => w[0]).slice(0, 2).join("");
  const palettes = { Slack: "#4A154B", PagerDuty: "#06AC38", Datadog: "#632CA6", Splunk: "#000000", Okta: "#007DC1",
    "Microsoft Entra ID": "#0078D4", Jira: "#0052CC", Linear: "#5E6AD2", Snowflake: "#29B5E8", BigQuery: "#4285F4",
    GitHub: "#181717", OpenAI: "#10A37F", Anthropic: "#C96442", "Google Gemini": "#4285F4", "AWS Bedrock": "#FF9900",
    "Epic FHIR": "#A02D2D" };
  return (
    <div className="integ-logo" style={{ background: palettes[name] || "#71717a" }}>{initials}</div>
  );
};

window.IntegrationsPage = IntegrationsPage;


/* ============================================================
   Audit engagement room
   /audits/:audit_id  — Sarah's workspace during an active audit.
   ============================================================ */

const AUDIT_TASKS = [
  { id: 1, control: "AC-2", title: "Provide evidence of access reviews", status: "in_review", due: "Nov 5", assigned: "Priya Sharma", comments: 3, evidenceCount: 2 },
  { id: 2, control: "AC-6", title: "Documented least-privilege procedures", status: "approved", due: "Oct 30", assigned: "Priya Sharma", comments: 1, evidenceCount: 1 },
  { id: 3, control: "AU-2", title: "Sample 30 traces with contradicted verdicts (Q3)", status: "pending", due: "Nov 8", assigned: "Mike Chen", comments: 0, evidenceCount: 0 },
  { id: 4, control: "AU-9", title: "Confirm Merkle anchor integrity for 2026-08-13", status: "approved", due: "Oct 28", assigned: "Mike Chen", comments: 4, evidenceCount: 3 },
  { id: 5, control: "SC-13", title: "Validate Ed25519 key rotation in Q3", status: "in_review", due: "Nov 6", assigned: "Mike Chen", comments: 2, evidenceCount: 1 },
  { id: 6, control: "SI-7", title: "Verify daily bulletin commits for full quarter", status: "pending", due: "Nov 10", assigned: "Priya Sharma", comments: 0, evidenceCount: 0 },
  { id: 7, control: "MP-6", title: "Confirm GDPR purge audit log for July purge", status: "blocked", due: "Nov 4", assigned: "Priya Sharma", comments: 5, evidenceCount: 1 },
];

const AuditRoomPage = ({ pushToast }) => {
  const [selectedTask, setSelectedTask] = React.useState(AUDIT_TASKS[0]);
  const [comment, setComment] = React.useState("");

  const total = AUDIT_TASKS.length;
  const approved = AUDIT_TASKS.filter((t) => t.status === "approved").length;
  const inReview = AUDIT_TASKS.filter((t) => t.status === "in_review").length;
  const blocked = AUDIT_TASKS.filter((t) => t.status === "blocked").length;

  return (
    <>
      <header className="page-header">
        <div className="page-header__inner">
          <div className="page-header__eyebrow">Compliance · audit room</div>
          <h1>Q3 2026 HIPAA audit</h1>
          <p className="page-header__sub">
            Active engagement with <strong>HIPAA Audit Partners</strong>. Opened Oct 18 · target sign-off Nov 12.
            {" "}{approved}/{total} controls approved · {inReview} in review · {blocked} blocked.
          </p>
        </div>
        <div className="page-actions">
          <Button variant="secondary" size="sm" icon={window.Icon.share({ size: 13 })}>Add auditor</Button>
          <Button variant="primary" size="sm" icon={window.Icon.fileCheck({ size: 13 })}>Final sign-off</Button>
        </div>
      </header>

      <div className="audit-progress">
        <div className="audit-progress__bar">
          <div className="audit-progress__fill audit-progress__fill--ok" style={{ width: `${(approved / total) * 100}%` }} />
          <div className="audit-progress__fill audit-progress__fill--review" style={{ width: `${(inReview / total) * 100}%` }} />
          <div className="audit-progress__fill audit-progress__fill--block" style={{ width: `${(blocked / total) * 100}%` }} />
        </div>
        <div className="audit-progress__legend">
          <span><span className="dot" style={{ background: "var(--verified)" }} /> Approved {approved}</span>
          <span><span className="dot" style={{ background: "var(--partial)" }} /> In review {inReview}</span>
          <span><span className="dot" style={{ background: "var(--contra)" }} /> Blocked {blocked}</span>
          <span><span className="dot" style={{ background: "var(--rule-strong)" }} /> Pending {total - approved - inReview - blocked}</span>
        </div>
      </div>

      <div className="audit-layout">
        {/* Tasks list */}
        <div className="audit-tasks">
          <div className="audit-tasks__header">
            <h3>Auditor requests</h3>
            <Button variant="ghost" size="sm" icon={window.Icon.plus({ size: 12 })}>Add request</Button>
          </div>
          {AUDIT_TASKS.map((task) => (
            <button key={task.id}
              className={`audit-task ${selectedTask.id === task.id ? "audit-task--active" : ""}`}
              onClick={() => setSelectedTask(task)}>
              <div className={`audit-task__status audit-task__status--${task.status}`}>
                {task.status === "approved" ? window.Icon.checkSimple({ size: 11 }) :
                 task.status === "blocked" ? window.Icon.xCircle({ size: 11 }) :
                 task.status === "in_review" ? window.Icon.clock({ size: 11 }) : null}
              </div>
              <div className="audit-task__body">
                <div className="audit-task__head">
                  <span className="audit-task__control mono">{task.control}</span>
                  <span className="audit-task__title">{task.title}</span>
                </div>
                <div className="audit-task__meta">
                  <span className="text-xs muted">Due {task.due}</span>
                  {task.comments > 0 && <span className="text-xs muted">· 💬 {task.comments}</span>}
                  {task.evidenceCount > 0 && <span className="text-xs muted">· 📎 {task.evidenceCount}</span>}
                </div>
              </div>
            </button>
          ))}
        </div>

        {/* Task detail */}
        <div className="audit-detail">
          <div className="audit-detail__head">
            <span className="audit-task__control mono">{selectedTask.control}</span>
            <Badge tone={selectedTask.status === "approved" ? "verified" : selectedTask.status === "in_review" ? "partial" : selectedTask.status === "blocked" ? "contra" : "neutral"}>
              {selectedTask.status === "in_review" ? "In review" : selectedTask.status === "approved" ? "Approved" : selectedTask.status === "blocked" ? "Blocked" : "Pending"}
            </Badge>
            <span className="spacer" />
            <span className="text-xs muted">Due {selectedTask.due}</span>
          </div>
          <h2 className="audit-detail__title">{selectedTask.title}</h2>
          <div className="audit-detail__assigned text-sm muted">
            Assigned to <strong>{selectedTask.assigned}</strong> · added by auditor 5 days ago
          </div>

          <div className="audit-section">
            <div className="audit-section__head">Evidence attached ({selectedTask.evidenceCount})</div>
            <div className="evidence-list">
              <EvidenceItem icon="fileCheck" name="Access-review-2026-Q3.pdf" size="412 KB" by="Priya Sharma · 2 days ago" hash="0xb2e9…71fa" />
              <EvidenceItem icon="fileCheck" name="audit-trail-AC-2.json" size="89 KB" by="System export · 2 days ago" hash="0x44b1…ee03" />
              <button className="audit-attach">
                <span>{window.Icon.upload({ size: 14 })}</span>
                <span className="text-sm">Drop file or click to upload evidence</span>
                <span className="text-xs muted">Files are hashed and added to the audit chain.</span>
              </button>
            </div>
          </div>

          <div className="audit-section">
            <div className="audit-section__head">Conversation</div>
            <div className="audit-thread">
              <AuditComment author="R. Chen (auditor)" external time="2 days ago" body="Could you also include the access review approval emails from the Q3 quarter? PDF or eml is fine." />
              <AuditComment author="Priya Sharma" time="1 day ago" body="Attached. The CTO-level approvals are on pages 8–12. Let me know if you need the signed originals." />
              <AuditComment author="R. Chen (auditor)" external time="6 hours ago" body="Got them — going through Friday. Will move to Approved unless I find anything." />
            </div>
            <div className="audit-compose">
              <textarea className="textarea" rows="2" placeholder="Reply…" value={comment} onChange={(e) => setComment(e.target.value)} />
              <div className="row gap-2" style={{ marginTop: 8 }}>
                <Button variant="ghost" size="sm" icon={window.Icon.upload({ size: 12 })}>Attach</Button>
                <span className="spacer" />
                <Button variant="primary" size="sm" disabled={!comment.trim()} onClick={() => { setComment(""); pushToast({ kind: "success", title: "Reply sent" }); }}>Send reply</Button>
              </div>
            </div>
          </div>
        </div>

        {/* Sidebar */}
        <aside className="audit-side">
          <div className="card card--padded">
            <div className="text-xs muted fw-600 mono" style={{ letterSpacing: "0.1em", textTransform: "uppercase" }}>Auditor</div>
            <div style={{ marginTop: 8, marginBottom: 12 }}>
              <div className="row gap-2">
                <div className="avatar" style={{ width: 28, height: 28 }}>RC</div>
                <div>
                  <div className="fw-600">R. Chen</div>
                  <div className="text-xs muted">HIPAA Audit Partners</div>
                </div>
                <span className="spacer" />
                <span className="presence-dot" title="Online" />
              </div>
            </div>
            <div className="audit-side__rows">
              <div className="row" style={{ justifyContent: "space-between" }}><span className="muted text-xs">Access</span><span className="text-xs">Read-only · all</span></div>
              <div className="row" style={{ justifyContent: "space-between" }}><span className="muted text-xs">Engagement</span><span className="text-xs">Q3 2026 HIPAA</span></div>
              <div className="row" style={{ justifyContent: "space-between" }}><span className="muted text-xs">Opened</span><span className="text-xs">Oct 18, 2026</span></div>
              <div className="row" style={{ justifyContent: "space-between" }}><span className="muted text-xs">Target sign-off</span><span className="text-xs">Nov 12, 2026</span></div>
            </div>
          </div>

          <div className="card card--padded">
            <div className="text-xs muted fw-600 mono" style={{ letterSpacing: "0.1em", textTransform: "uppercase", marginBottom: 8 }}>Engagement seal</div>
            <div className="text-sm muted" style={{ marginBottom: 8 }}>
              Every comment, evidence upload, and status change is signed and added to the audit chain.
            </div>
            <div className="audit-side__rows">
              <div className="row" style={{ justifyContent: "space-between" }}><span className="muted text-xs">Chain root</span><HashChip value="0x7f0…9c3a" short="0x7f0…9c3a" /></div>
              <div className="row" style={{ justifyContent: "space-between" }}><span className="muted text-xs">Events</span><span className="mono text-xs">38 logged</span></div>
            </div>
            <Button variant="link" size="sm" iconRight={window.Icon.external({ size: 11 })} style={{ marginTop: 6 }}>View audit chain</Button>
          </div>
        </aside>
      </div>
    </>
  );
};

const EvidenceItem = ({ icon, name, size, by, hash }) => (
  <div className="evidence-item">
    <div className="evidence-item__icon">{window.Icon[icon]({ size: 14 })}</div>
    <div className="evidence-item__body">
      <div className="fw-600 text-sm">{name}</div>
      <div className="text-xs muted">{size} · {by}</div>
    </div>
    <HashChip value={hash} short={hash} />
    <Button variant="ghost" size="sm" icon={window.Icon.download({ size: 12 })} />
  </div>
);

const AuditComment = ({ author, external, time, body }) => (
  <div className={`audit-comment ${external ? "audit-comment--external" : ""}`}>
    <div className="avatar" style={{ width: 26, height: 26, flexShrink: 0 }}>
      {author.split(" ").map((w) => w[0]).slice(0, 2).join("")}
    </div>
    <div className="audit-comment__body">
      <div className="row gap-2">
        <span className="fw-600 text-sm">{author}</span>
        {external && <Badge tone="info">External</Badge>}
        <span className="text-xs muted">· {time}</span>
      </div>
      <div className="text-sm" style={{ marginTop: 4, color: "var(--ink-2)", lineHeight: 1.5 }}>{body}</div>
    </div>
  </div>
);

window.AuditRoomPage = AuditRoomPage;


/* ============================================================
   Analytics — cost & latency dashboards
   ============================================================ */

const ALL_VERDICT_COLORS = { verified: "#2f6e47", partial: "#9a6418", unverif: "#71717a", contra: "#9b2c2c" };

const AnalyticsPage = () => {
  const [tab, setTab] = React.useState("cost");

  return (
    <>
      <header className="page-header">
        <div className="page-header__inner">
          <div className="page-header__eyebrow">Workspace · Analytics</div>
          <h1>Analytics</h1>
          <p className="page-header__sub">Spend, performance, and judge calibration across every wrapped call.</p>
        </div>
        <div className="page-actions">
          <Button variant="secondary" size="sm" iconRight={window.Icon.chevronDown({ size: 12 })}>Last 30 days</Button>
          <Button variant="secondary" size="sm" icon={window.Icon.download({ size: 12 })}>Export CSV</Button>
        </div>
      </header>

      <Tabs items={[
        { value: "cost", label: "Cost" },
        { value: "latency", label: "Latency · performance" },
        { value: "calibration", label: "Judge calibration" },
      ]} value={tab} onChange={setTab} />

      {tab === "cost" && <CostTab />}
      {tab === "latency" && <LatencyTab />}
      {tab === "calibration" && <CalibrationTab />}
    </>
  );
};

const CostTab = () => {
  const days = 30;
  const data = React.useMemo(() => Array.from({ length: days }, (_, i) => ({
    label: `D${i + 1}`,
    encounter: 2.4 + Math.sin(i / 3) * 0.6 + (i / 25),
    discharge: 1.2 + Math.cos(i / 4) * 0.3 + (i / 60),
    triage: 0.5 + Math.sin(i / 5) * 0.2 + (i / 80),
  })), []);
  const total = data.reduce((sum, d) => sum + d.encounter + d.discharge + d.triage, 0).toFixed(2);

  return (
    <div className="col gap-4">
      <div className="apps-summary">
        <SummaryStat label="Spend (30d)" value={`$${total}`} />
        <SummaryStat label="Avg / call" value="$0.014" />
        <SummaryStat label="Most expensive app" value="Encounter" />
        <SummaryStat label="Anomalies" value="1" />
      </div>

      <Card title="Daily spend by app" meta="Stacked · last 30 days" padded={false}>
        <div className="chart-area" style={{ height: 240 }}>
          <CostStacked data={data} w={1080} h={240} />
        </div>
      </Card>

      <div className="dash-grid">
        <Card title="Spend by model" padded>
          <div className="col gap-3">
            <CostRow label="gpt-4o-mini" pct={62} value="$54.10" />
            <CostRow label="claude-3-5-sonnet" pct={24} value="$20.93" />
            <CostRow label="gemini-1.5-pro" pct={10} value="$8.72" />
            <CostRow label="lynx-8b (judge)" pct={4} value="$3.51" />
          </div>
        </Card>
        <Card title="Top cost outliers" padded>
          <div className="col gap-2 text-sm">
            <div className="row gap-2"><HashChip value="af_dt5…f04" short="af_dt5…f04" /><span className="spacer" /><span className="mono fw-600">$0.18</span></div>
            <div className="row gap-2"><HashChip value="af_8nm…rt4" short="af_8nm…rt4" /><span className="spacer" /><span className="mono fw-600">$0.14</span></div>
            <div className="row gap-2"><HashChip value="af_5bp…ku9" short="af_5bp…ku9" /><span className="spacer" /><span className="mono fw-600">$0.12</span></div>
            <div className="text-xs muted" style={{ marginTop: 8 }}>Outliers typically involve long context (10K+ tokens) or contradicted-claim re-verification.</div>
          </div>
        </Card>
      </div>
    </div>
  );
};

const CostStacked = ({ data, w, h }) => {
  const innerW = w - 30;
  const innerH = h - 30;
  const dx = innerW / (data.length - 1);
  const maxT = Math.max(...data.map((d) => d.encounter + d.discharge + d.triage));
  const cols = ["encounter", "discharge", "triage"];
  const colors = ["#0f0f12", "#3f3f46", "#a1a1aa"];

  const paths = cols.map((k, s) => {
    let p = "";
    data.forEach((d, i) => {
      const top = cols.slice(0, s + 1).reduce((a, b) => a + d[b], 0);
      const y = innerH - (top / maxT) * innerH;
      p += `${i === 0 ? "M" : "L"} ${15 + i * dx} ${10 + y} `;
    });
    for (let i = data.length - 1; i >= 0; i--) {
      const bot = s === 0 ? 0 : cols.slice(0, s).reduce((a, b) => a + data[i][b], 0);
      const y = innerH - (bot / maxT) * innerH;
      p += `L ${15 + i * dx} ${10 + y} `;
    }
    p += "Z";
    return <path key={k} d={p} fill={colors[s]} fillOpacity={0.85 - s * 0.2} />;
  });

  return (
    <svg viewBox={`0 0 ${w} ${h}`} width="100%" height={h}>
      {[0.25, 0.5, 0.75, 1].map((t) => <line key={t} x1="15" y1={10 + innerH * (1 - t)} x2={w - 15} y2={10 + innerH * (1 - t)} stroke="var(--rule)" strokeDasharray="2 4" />)}
      {paths}
      {[0, 9, 19, 29].map((i) => <text key={i} x={15 + i * dx} y={h - 6} fontSize="10" fontFamily="Geist Mono, monospace" fill="var(--ink-4)" textAnchor="middle">Day {i + 1}</text>)}
    </svg>
  );
};

const CostRow = ({ label, pct, value }) => (
  <div>
    <div className="row gap-2" style={{ marginBottom: 6 }}>
      <span className="fw-500">{label}</span>
      <span className="spacer" />
      <span className="mono tabular fw-600">{value}</span>
      <span className="text-xs muted mono tabular" style={{ width: 38, textAlign: "right" }}>{pct}%</span>
    </div>
    <div className="progress"><div className="progress__bar" style={{ width: `${pct}%` }} /></div>
  </div>
);

const LatencyTab = () => (
  <div className="col gap-4">
    <div className="apps-summary">
      <SummaryStat label="p50 (30d)" value="218 ms" />
      <SummaryStat label="p95" value="612 ms" />
      <SummaryStat label="p99" value="1.42 s" />
      <SummaryStat label="Seal latency" value="14 ms" />
    </div>

    <Card title="End-to-end latency · percentile bands" meta="Forward → respond → claim → verify → seal" padded={false}>
      <div className="chart-area" style={{ height: 240 }}>
        <LatencyChart w={1080} h={240} />
      </div>
    </Card>

    <div className="dash-grid">
      <Card title="Latency by stage" padded>
        <div className="col gap-3">
          <StageRow label="SDK → edge" v="14ms" pct={5} />
          <StageRow label="PHI redaction" v="22ms" pct={8} />
          <StageRow label="LLM call (provider)" v="1,108ms" pct={66} />
          <StageRow label="Claim extraction" v="148ms" pct={9} />
          <StageRow label="Multi-judge verification" v="294ms" pct={11} />
          <StageRow label="Seal · bulletin write" v="14ms" pct={1} />
        </div>
      </Card>
      <Card title="Sandbox capacity" padded>
        <div className="col gap-3">
          <div className="row gap-2"><span className="muted">Tier</span><span className="spacer" /><Badge tone="info">Standard · 3 judges</Badge></div>
          <div className="row gap-2"><span className="muted">Concurrent verifications</span><span className="spacer" /><span className="mono">8 / 12</span></div>
          <div className="row gap-2"><span className="muted">Queue depth</span><span className="spacer" /><span className="mono">0</span></div>
          <div className="row gap-2"><span className="muted">Region</span><span className="spacer" /><span>US-East (BAA)</span></div>
          <div className="text-xs muted" style={{ marginTop: 8 }}>The verifier sandbox is sized to your peak hourly call rate × 1.5 — upgrade if p95 verification queue time exceeds 5 seconds.</div>
        </div>
      </Card>
    </div>
  </div>
);

const StageRow = ({ label, v, pct }) => (
  <div>
    <div className="row gap-2" style={{ marginBottom: 6 }}>
      <span className="fw-500 text-sm">{label}</span>
      <span className="spacer" />
      <span className="mono tabular text-sm">{v}</span>
    </div>
    <div className="progress" style={{ height: 4 }}><div className="progress__bar" style={{ width: `${pct}%` }} /></div>
  </div>
);

const LatencyChart = ({ w, h }) => {
  const days = 30;
  const data = Array.from({ length: days }, (_, i) => ({
    p50: 180 + Math.sin(i / 4) * 30 + (i / 4),
    p95: 480 + Math.sin(i / 3) * 80 + (i / 2),
    p99: 1100 + Math.cos(i / 5) * 200 + (i),
  }));
  const innerW = w - 30; const innerH = h - 30;
  const dx = innerW / (days - 1);
  const max = 1800;
  const pathFor = (k) => data.map((d, i) => `${i === 0 ? "M" : "L"} ${15 + i * dx} ${10 + innerH - (d[k] / max) * innerH}`).join(" ");

  return (
    <svg viewBox={`0 0 ${w} ${h}`} width="100%" height={h}>
      {[0.25, 0.5, 0.75, 1].map((t) => <line key={t} x1="15" y1={10 + innerH * (1 - t)} x2={w - 15} y2={10 + innerH * (1 - t)} stroke="var(--rule)" strokeDasharray="2 4" />)}
      <path d={pathFor("p99")} fill="none" stroke="#9b2c2c" strokeWidth="1.5" opacity="0.85" />
      <path d={pathFor("p95")} fill="none" stroke="#9a6418" strokeWidth="1.5" opacity="0.85" />
      <path d={pathFor("p50")} fill="none" stroke="#0f0f12" strokeWidth="2" />
      <g>
        {[0, 9, 19, 29].map((i) => <text key={i} x={15 + i * dx} y={h - 6} fontSize="10" fontFamily="Geist Mono, monospace" fill="var(--ink-4)" textAnchor="middle">Day {i + 1}</text>)}
      </g>
      <g fontSize="10" fontFamily="Geist Mono, monospace">
        <text x={w - 50} y={20} fill="#0f0f12" fontWeight="600">p50</text>
        <text x={w - 50} y={36} fill="#9a6418" fontWeight="600">p95</text>
        <text x={w - 50} y={52} fill="#9b2c2c" fontWeight="600">p99</text>
      </g>
    </svg>
  );
};

const CalibrationTab = () => (
  <div className="col gap-4">
    <div className="apps-summary">
      <SummaryStat label="Avg Cohen's κ" value="0.88" />
      <SummaryStat label="Calibrated runs" value="94.2%" />
      <SummaryStat label="Below 0.7" value="142" />
      <SummaryStat label="Judges active" value="3" />
    </div>
    <Card title="Calibration over time" meta="Cohen's κ across all judges, last 90 days" padded>
      <div className="text-sm muted">Drops below the 0.7 threshold are auto-surfaced in the compliance dashboard. Judges are versioned and signed — if any judge updates, its content-addressed identity changes and the verifier flags the recalibration.</div>
    </Card>
  </div>
);

window.AnalyticsPage = AnalyticsPage;


/* ============================================================
   Risk register
   ============================================================ */

const RISKS = [
  { id: "R-014", title: "Encounter Summary contradiction rate elevated", sev: "high", status: "open", owner: "Priya Sharma", framework: "HIPAA · Article 12", opened: "Oct 14", desc: "Contradiction rate rose 3.1× following AHA HF guideline v2.2 publication. Risk to clinical accuracy.", linked: 4 },
  { id: "R-013", title: "Source registry drift · ICD-10-CM 2025", sev: "medium", status: "mitigating", owner: "Mike Chen", framework: "FDA 21 CFR 11", opened: "Oct 09", desc: "Annual code-set update not yet ingested. 12 calls/day verify against last year's codes.", linked: 12 },
  { id: "R-012", title: "Sandbox unhealthy event >5 min duration", sev: "medium", status: "mitigating", owner: "Mike Chen", framework: "Internal SLO", opened: "Oct 02", desc: "Single 8-minute unhealthy window Oct 2. Calls queued, no data loss, but breached internal SLO.", linked: 1 },
  { id: "R-011", title: "Auditor share-link recipient ambiguity", sev: "low", status: "accepted", owner: "Priya Sharma", framework: "Internal policy", opened: "Sep 28", desc: "Share links sent before formal auditor onboarding sometimes go to wrong recipient.", linked: 0 },
  { id: "R-010", title: "Free-tier rate limit hit during Q3 surge", sev: "low", status: "resolved", owner: "Mike Chen", framework: "Internal SLO", opened: "Aug 19", desc: "13 calls returned 429 during a 4-minute window. Resolved via plan upgrade.", linked: 0 },
  { id: "R-009", title: "PHI surrogate collision possibility", sev: "high", status: "mitigated", owner: "Mike Chen", framework: "HIPAA", opened: "Aug 02", desc: "Theoretical collision rate for surrogate names was 1 in 10M. Increased surrogate space to 1 in 10B.", linked: 0 },
];

const sevColors = { high: "var(--contra)", medium: "var(--partial)", low: "var(--ink-3)" };

const RiskRegisterPage = () => {
  const [statusF, setStatusF] = React.useState("active");
  const filtered = RISKS.filter((r) => {
    if (statusF === "active") return ["open", "mitigating"].includes(r.status);
    if (statusF === "all") return true;
    return r.status === statusF;
  });

  return (
    <>
      <header className="page-header">
        <div className="page-header__inner">
          <div className="page-header__eyebrow">Compliance · risk</div>
          <h1>Risk register</h1>
          <p className="page-header__sub">Identified risks, owners, mitigation status. Every entry signs into the audit chain — changes are tamper-evident.</p>
        </div>
        <div className="page-actions">
          <Button variant="secondary" size="sm" icon={window.Icon.download({ size: 12 })}>Export CSV</Button>
          <Button variant="primary" size="sm" icon={window.Icon.plus({ size: 13 })}>Log risk</Button>
        </div>
      </header>

      <div className="apps-summary">
        <SummaryStat label="Active risks" value={RISKS.filter(r => ["open","mitigating"].includes(r.status)).length} />
        <SummaryStat label="High severity" value={RISKS.filter(r => r.sev === "high" && ["open","mitigating"].includes(r.status)).length} />
        <SummaryStat label="Mitigated · resolved" value={RISKS.filter(r => ["mitigated","resolved"].includes(r.status)).length} />
        <SummaryStat label="Median age" value="12 days" />
      </div>

      <div className="toolbar">
        <div className="segmented">
          <button className={statusF === "active" ? "active" : ""} onClick={() => setStatusF("active")}>Active</button>
          <button className={statusF === "open" ? "active" : ""} onClick={() => setStatusF("open")}>Open</button>
          <button className={statusF === "mitigating" ? "active" : ""} onClick={() => setStatusF("mitigating")}>Mitigating</button>
          <button className={statusF === "resolved" ? "active" : ""} onClick={() => setStatusF("resolved")}>Resolved</button>
          <button className={statusF === "all" ? "active" : ""} onClick={() => setStatusF("all")}>All</button>
        </div>
        <div className="spacer" />
        <span className="text-xs muted">{filtered.length} shown</span>
      </div>

      <Card padded={false}>
        <table className="table">
          <thead>
            <tr>
              <th style={{ width: 80 }}>ID</th>
              <th>Risk</th>
              <th style={{ width: 90 }}>Severity</th>
              <th style={{ width: 130 }}>Status</th>
              <th>Framework</th>
              <th>Owner</th>
              <th style={{ width: 90 }}>Opened</th>
              <th style={{ width: 70, textAlign: "right" }}>Linked</th>
            </tr>
          </thead>
          <tbody>
            {filtered.map((r) => (
              <tr key={r.id} className="clickable">
                <td className="mono fw-600">{r.id}</td>
                <td>
                  <div className="fw-500">{r.title}</div>
                  <div className="text-xs muted" style={{ marginTop: 2, maxWidth: "60ch" }}>{r.desc}</div>
                </td>
                <td>
                  <span className="sev-chip" style={{ color: sevColors[r.sev] }}>
                    <span className="sev-dot" style={{ background: sevColors[r.sev] }} />
                    {r.sev.toUpperCase()}
                  </span>
                </td>
                <td>
                  {r.status === "open" && <Badge tone="contra" icon={window.Icon.warning({ size: 10 })}>Open</Badge>}
                  {r.status === "mitigating" && <Badge tone="partial" icon={window.Icon.clock({ size: 10 })}>Mitigating</Badge>}
                  {r.status === "mitigated" && <Badge tone="sealed" icon={window.Icon.checkSimple({ size: 10 })}>Mitigated</Badge>}
                  {r.status === "resolved" && <Badge tone="sealed" icon={window.Icon.checkSimple({ size: 10 })}>Resolved</Badge>}
                  {r.status === "accepted" && <Badge tone="info">Accepted</Badge>}
                </td>
                <td className="text-sm mono">{r.framework}</td>
                <td className="text-sm">{r.owner}</td>
                <td className="text-sm muted">{r.opened}</td>
                <td className="mono tabular text-sm" style={{ textAlign: "right" }}>{r.linked || "—"}</td>
              </tr>
            ))}
          </tbody>
        </table>
      </Card>
    </>
  );
};

window.RiskRegisterPage = RiskRegisterPage;
