/* Trace detail / replay — the killer screen.
   States: verified | contradicted | sandbox | diverge | auditor */

const STEPS = [
  { id: "inbound",    label: "Inbound request", icon: "arrowRight",  time: "10:34:01.234", meta: "POST /v1/wrap" },
  { id: "redaction",  label: "PHI redaction",   icon: "shield",      time: "10:34:01.290", meta: "4 entities redacted" },
  { id: "llm",        label: "LLM call (OpenAI)", icon: "zap",       time: "10:34:01.342", meta: "gpt-4o-mini · 1,234 tokens · $0.012" },
  { id: "extraction", label: "Claim extraction", icon: "fileText",   time: "10:34:01.890", meta: "3 claims extracted" },
  { id: "verify",     label: "Verification",     icon: "check",      time: "10:34:02.987", meta: "3/3 verified · κ 0.92" },
  { id: "seal",       label: "Evidence sealed",  icon: "lock",       time: "10:34:03.012", meta: "Block #1,247 · leaf 23" },
];

const TraceReplay = ({ state, auditor, onChangeState, onBack, pushToast, onOpenAuditor }) => {
  const [stepId, setStepId] = React.useState("verify");
  const [claimIdx, setClaimIdx] = React.useState(0);
  const [showReplayModal, setShowReplayModal] = React.useState(false);
  const [showShareModal, setShowShareModal] = React.useState(false);
  const [rawVotesOpen, setRawVotesOpen] = React.useState(false);
  const [replayRunning, setReplayRunning] = React.useState(false);
  const [shareState, setShareState] = React.useState({ stage: "form", expiry: "7", email: "r.chen@hipaa-audit-partners.com", note: "" });
  const [activeShare, setActiveShare] = React.useState(null); // { token, email, expiry, sharedAt }

  const t = SCENARIO.trace;

  // Verdict by state
  const isContradicted = state === "contradicted";
  const isSandbox = state === "sandbox";
  const isDiverge = state === "diverge";

  const overallVerdict = isContradicted ? "contra" : isSandbox ? "pending" : "verified";
  const verifyStepStatus = isSandbox ? "failed" : isContradicted ? "done-warn" : "done";

  // Step status per state
  const stepStatus = (id) => {
    const order = STEPS.findIndex((s) => s.id === id);
    if (isSandbox) {
      if (order < 4) return "done";
      if (order === 4) return "failed";  // verify failed/pending
      return "pending";
    }
    return order < STEPS.length ? "done" : "done";
  };

  // Active claim
  const claims = isContradicted
    ? [SCENARIO.claims.verified[0], SCENARIO.claims.contradicted[0], SCENARIO.claims.verified[2]]
    : SCENARIO.claims.verified;

  const claim = claims[claimIdx] || claims[0];

  const onReplay = () => {
    setShowReplayModal(false);
    setReplayRunning(true);
    setTimeout(() => {
      setReplayRunning(false);
      if (isDiverge) {
        pushToast({ kind: "warn", title: "Replay verdict diverges", sub: "1 of 3 sources updated since original. See diff below." });
      } else {
        pushToast({ kind: "success", title: "Replay verified", sub: "Original verdict still holds. Trace marked Replay-verified." });
      }
    }, 1800);
  };

  return (
    <>
      {auditor && (
        <div className="auditor-banner">
          <div className="auditor-banner__badge">{window.Icon.eye({ size: 20 })}</div>
          <div className="auditor-banner__body">
            <div className="auditor-banner__title">Auditor view · read-only · valid 7 days</div>
            <div className="auditor-banner__sub">
              You're viewing a shared trace from <strong>{SCENARIO.tenant.name}</strong>. To verify the cryptographic chain offline, download the bundle and run <span className="mono" style={{ background: "var(--code-bg)", padding: "1px 6px", borderRadius: 3 }}>attestia verify ./bundle.zip</span>.
            </div>
          </div>
          <div className="row gap-2">
            <Button variant="secondary" size="sm" icon={window.Icon.download({ size: 14 })}>Download bundle</Button>
            <Button variant="ghost" size="sm" icon={window.Icon.external({ size: 12 })}>Get CLI</Button>
          </div>
        </div>
      )}

      {/* Header strip — document spread */}
      <div className="tr-header">
        <div className="tr-header__crumb">
          <button className="btn btn--ghost btn--sm" onClick={onBack} style={{ padding: "0 4px", height: 22, letterSpacing: 0, textTransform: "none", fontFamily: "var(--font-sans)" }}>
            {window.Icon.arrowLeft({ size: 12 })} Traces
          </button>
          <span style={{ color: "var(--ink-4)" }}>/</span>
          <span className="mono">{t.short}</span>
        </div>
        <div className="tr-header__title">
          <h1>
            Trace <span className="mono">{t.short}</span>
          </h1>
          <div className="tr-header__verdict-col">
            <Verdict kind={overallVerdict} size="lg" label={isSandbox ? "Verification pending" : isContradicted ? "Contradicted" : "Verified"} />
            {isDiverge && <Badge tone="partial" icon={window.Icon.alertTriangle({ size: 11 })} size="lg">Replay diverged</Badge>}
          </div>
        </div>
        <div className="tr-header__meta">
          <div>
            <span className="col-label">App</span>
            <span className="col-value">{t.app}</span>
          </div>
          <div>
            <span className="col-label">Purpose</span>
            <span className="col-value mono">{t.purpose}</span>
          </div>
          <div>
            <span className="col-label">User tag</span>
            <span className="col-value mono">{t.userTag}</span>
          </div>
          <div>
            <span className="col-label">Sealed</span>
            <span className="col-value">{t.timestamp}</span>
          </div>
          <div className="col-actions">
            {!auditor && (
              <Button variant="secondary" size="sm" iconRight={window.Icon.replay({ size: 12 })} onClick={() => setShowReplayModal(true)}>
                Replay this call
              </Button>
            )}
          </div>
        </div>
      </div>

      {/* Active share indicator — visible once the user has shared */}
      {activeShare && !auditor && (
        <div className="active-share">
          <div className="active-share__icon">{window.Icon.share({ size: 14 })}</div>
          <div className="active-share__body">
            <span className="active-share__label">Shared with auditor</span>
            <span className="active-share__sep">·</span>
            {activeShare.email && <><span>{activeShare.email}</span><span className="active-share__sep">·</span></>}
            <span>{activeShare.expiry} days remaining</span>
            <span className="active-share__sep">·</span>
            <span className="mono text-xs">audit.attestia.ai/share/{activeShare.token}</span>
          </div>
          <Button variant="ghost" size="sm" icon={window.Icon.copy({ size: 12 })}
            onClick={() => pushToast({ kind: "success", title: "Link copied" })}>Copy</Button>
          <Button variant="ghost" size="sm" onClick={() => onOpenAuditor && onOpenAuditor()}>Preview</Button>
          <button className="active-share__close" onClick={() => setActiveShare(null)} aria-label="Revoke share">
            {window.Icon.x({ size: 12 })}
          </button>
        </div>
      )}

      {/* State banners */}
      {isSandbox && (
        <div className="state-banner state-banner--warn">
          <div className="state-banner__icon">{window.Icon.alertTriangle({ size: 14 })}</div>
          <div style={{ flex: 1 }}>
            <div className="state-banner__title">Verification queued — sandbox unreachable</div>
            <div className="state-banner__sub">
              Your call was forwarded to OpenAI and the response is stored. The verification sandbox is temporarily unreachable; we'll retry automatically.
              Trace stored 10:34:01 UTC · queued 38s ago · next retry in 22s.
            </div>
            <div className="state-banner__actions">
              <Button variant="secondary" size="sm" icon={window.Icon.rotateCw({ size: 12 })}>Manual retry</Button>
              <Button variant="ghost" size="sm">View original LLM response</Button>
            </div>
          </div>
        </div>
      )}

      {isDiverge && (
        <div className="state-banner state-banner--warn">
          <div className="state-banner__icon">{window.Icon.alertTriangle({ size: 14 })}</div>
          <div style={{ flex: 1 }}>
            <div className="state-banner__title">Replay verdict diverges from original</div>
            <div className="state-banner__sub">
              Source <strong>AHA/ACC Heart Failure Guidelines 2024</strong> was re-indexed on 2026-10-22 (v2.1 → v2.2). The replay uses the current version; the original used the version live at trace time.
            </div>
            <div className="diverge">
              <div className="diverge__col">
                <div className="diverge__head">Original (Oct 24, 10:34 UTC)</div>
                <div className="diverge__row"><span>Verdict</span><span>✓ Verified</span></div>
                <div className="diverge__row"><span>Cohen's κ</span><span className="mono">0.92</span></div>
                <div className="diverge__row"><span>Sources cited</span><span>3</span></div>
                <div className="diverge__row"><span>Source version</span><span className="mono">aha-hf24-v2.1</span></div>
              </div>
              <div className="diverge__col">
                <div className="diverge__head">Replay (just now)</div>
                <div className="diverge__row"><span>Verdict</span><span style={{ color: "var(--partial)" }}>▲ Partial</span></div>
                <div className="diverge__row"><span>Cohen's κ</span><span className="mono">0.74</span></div>
                <div className="diverge__row"><span>Sources cited</span><span>2 (1 updated)</span></div>
                <div className="diverge__row"><span>Source version</span><span className="mono">aha-hf24-v2.2</span></div>
              </div>
            </div>
            <div className="state-banner__actions">
              <Button variant="secondary" size="sm">View source diff</Button>
              <Button variant="ghost" size="sm">Accept replay as new evidence</Button>
            </div>
          </div>
        </div>
      )}

      {/* Body: timeline + step detail */}
      <div className="tr-body">
        <div className="timeline">
          <div className="timeline__title">Lifecycle</div>
          {STEPS.map((s) => {
            const status = stepStatus(s.id);
            const isActive = stepId === s.id;
            return (
              <div
                key={s.id}
                className={`tl-step tl-step--${status} ${isActive ? "tl-step--active" : ""}`}
                onClick={() => setStepId(s.id)}
              >
                <div className="tl-step__rail">
                  <div className="tl-step__icon">
                    {status === "done" || status === "done-warn"
                      ? window.Icon.checkSimple({ size: 11 })
                      : status === "failed"
                        ? window.Icon.alertTriangle({ size: 11 })
                        : status === "pending"
                          ? <span style={{ width: 4, height: 4, borderRadius: "50%", background: "currentColor" }} />
                          : window.Icon.checkSimple({ size: 11 })}
                  </div>
                  <div className="tl-step__line" />
                </div>
                <div className="tl-step__body">
                  <div className="tl-step__head">
                    {s.label}
                    {isActive && <Badge tone="info" size="lg" style={{ marginLeft: "auto" }}>Active</Badge>}
                  </div>
                  <div className="tl-step__time">{isSandbox && s.id === "verify" ? "queued · 38s ago" : s.time}</div>
                  <div className="tl-step__meta">
                    {isSandbox && s.id === "verify" ? "sandbox unreachable · retry queued"
                      : isContradicted && s.id === "verify" ? "1 contradicted · 2 verified · κ 0.95"
                      : s.meta}
                  </div>
                </div>
              </div>
            );
          })}

          <div className="timeline__footer">
            <div>Total duration<strong>{isSandbox ? "—" : t.duration}</strong></div>
            <div>Cost<strong>{t.cost}</strong></div>
          </div>
        </div>

        {/* Step detail panel */}
        <div>
          <StepDetail
            stepId={stepId}
            claim={claim}
            claims={claims}
            claimIdx={claimIdx}
            setClaimIdx={setClaimIdx}
            isContradicted={isContradicted}
            isSandbox={isSandbox}
            onShowRaw={() => setRawVotesOpen(true)}
          />

          {/* Evidence seal — always visible */}
          <EvidenceSeal
            isPending={isSandbox}
            isContradicted={isContradicted}
            auditor={auditor}
            onReplay={() => setShowReplayModal(true)}
            onShare={() => setShowShareModal(true)}
          />
        </div>
      </div>

      {/* Replay modal */}
      <Modal
        open={showReplayModal}
        onClose={() => setShowReplayModal(false)}
        title="Replay this call"
        sub="Re-run verification with the same inputs. Sources resolved to current version."
        footer={
          <>
            <Button variant="ghost" onClick={() => setShowReplayModal(false)}>Cancel</Button>
            <Button variant="primary" onClick={onReplay} icon={window.Icon.replay({ size: 14 })}>Run replay</Button>
          </>
        }
      >
        <div className="col gap-4">
          <div className="preset-detail__rows">
            <PresetRow label="Inputs" value="Original LLM response · 3 claims · 4 redactions" />
            <PresetRow label="Sources" value={`${SCENARIO.sources.length} active · resolved to current version`} />
            <PresetRow label="Judges" value="3-judge consensus (Lynx, Claude, Gemini)" />
            <PresetRow label="Output" value="Verdict + κ + per-judge votes. Tamper-evident if diverges." />
          </div>
          <div className="onb-note" style={{ background: "var(--paper-alt)", borderColor: "var(--rule)" }}>
            <span style={{ color: "var(--brand-ink)" }}>{window.Icon.shield({ size: 14 })}</span>
            <div>Replay does not call the LLM again. Same inputs, same judge pool, ~15s typical runtime.</div>
          </div>
        </div>
      </Modal>

      {/* Share modal — form → generated link → email-sent confirmation */}
      <Modal
        open={showShareModal}
        onClose={() => { setShowShareModal(false); setShareState({ ...shareState, stage: "form" }); }}
        title={shareState.stage === "form" ? "Share with auditor" : shareState.stage === "generated" ? "Signed link generated" : "Email sent"}
        sub={shareState.stage === "form"
          ? "Signed link valid up to 30 days. Auditor can verify offline — no Attestia account needed."
          : shareState.stage === "generated"
          ? "Copy the link, or email it directly with verification instructions. Anyone with this link can view the trace and download the evidence bundle."
          : `We sent the link to ${shareState.email}. They have ${shareState.expiry} days to verify.`}
        wide
        footer={shareState.stage === "form" ? (
          <>
            <Button variant="ghost" onClick={() => setShowShareModal(false)}>Cancel</Button>
            <Button variant="primary" onClick={() => setShareState({ ...shareState, stage: "generated" })} icon={window.Icon.share({ size: 14 })}>Generate signed link</Button>
          </>
        ) : shareState.stage === "generated" ? (
          <>
            <Button variant="ghost" onClick={() => {
              const share = { token: "eyJ0eXAi…aZ4r", email: null, expiry: shareState.expiry, sharedAt: new Date(), note: shareState.note };
              setActiveShare(share);
              setShowShareModal(false);
              setShareState({ ...shareState, stage: "form" });
              pushToast({ kind: "success", title: "Link copied", sub: `Auditor link valid ${shareState.expiry} days.` });
            }}>Just copy the link</Button>
            <Button variant="primary" onClick={() => setShareState({ ...shareState, stage: "sent" })} icon={window.Icon.share({ size: 14 })}>
              Email and copy
            </Button>
          </>
        ) : (
          <>
            <Button variant="ghost" onClick={() => onOpenAuditor && onOpenAuditor()}>Preview auditor view</Button>
            <Button variant="primary" onClick={() => {
              const share = { token: "eyJ0eXAi…aZ4r", email: shareState.email, expiry: shareState.expiry, sharedAt: new Date(), note: shareState.note };
              setActiveShare(share);
              setShowShareModal(false);
              setShareState({ ...shareState, stage: "form" });
              pushToast({ kind: "success", title: "Shared with auditor", sub: `${shareState.email} · ${shareState.expiry}-day signed link.` });
            }}>Done</Button>
          </>
        )}
      >
        {shareState.stage === "form" && (
          <div className="col gap-4">
            <Field label="Expires in">
              <div className="radio-row">
                {[{ v: "7", label: "7 days", sub: "Recommended" }, { v: "14", label: "14 days", sub: "Standard audit window" }, { v: "30", label: "30 days", sub: "Max — extended audits" }].map((o) => (
                  <RadioCard key={o.v} selected={shareState.expiry === o.v} title={o.label} sub={o.sub}
                    onClick={() => setShareState({ ...shareState, expiry: o.v })} />
                ))}
              </div>
            </Field>
            <Field label="Auditor email" hint="Optional. We'll email them with verification instructions and offline-CLI download link.">
              <input className="input" placeholder="auditor@firm.com" value={shareState.email}
                onChange={(e) => setShareState({ ...shareState, email: e.target.value })} />
            </Field>
            <Field label="Note" hint="Optional. Visible to the auditor in the shared view.">
              <textarea className="textarea" rows="2" placeholder="Q3 board review · please verify Block 1247 leaf 23."
                value={shareState.note} onChange={(e) => setShareState({ ...shareState, note: e.target.value })} />
            </Field>
            <div className="onb-note">
              <span style={{ color: "var(--ink-1)" }}>{window.Icon.shield({ size: 14 })}</span>
              <div className="text-sm">
                <strong>Includes:</strong> trace timeline, all claims + sources, multi-judge votes, evidence hash, Merkle position, bulletin reference, and a downloadable .zip with the offline-verify CLI.
              </div>
            </div>
          </div>
        )}

        {shareState.stage === "generated" && (
          <div className="col gap-4">
            <div className="share-link">
              <div className="share-link__row">
                <span style={{ color: "var(--ink-3)" }}>{window.Icon.link({ size: 14 })}</span>
                <span className="mono text-sm truncate" style={{ flex: 1 }}>
                  https://audit.attestia.ai/share/{shareState.expiry === "7" ? "eyJ0eXAi…aZ4r" : shareState.expiry === "14" ? "kPx8aQp…11Cy" : "mQv2nLk…9zR3"}
                </span>
                <Button variant="ghost" size="sm" icon={window.Icon.copy({ size: 12 })}
                  onClick={() => pushToast({ kind: "success", title: "Copied" })}>
                  Copy
                </Button>
              </div>
            </div>
            <div className="share-meta">
              <div className="share-meta__row">
                <span className="muted">Token</span>
                <span className="mono">JWT · ES256 · 1024-bit</span>
              </div>
              <div className="share-meta__row">
                <span className="muted">Scope</span>
                <span>Read-only · this trace + bundle</span>
              </div>
              <div className="share-meta__row">
                <span className="muted">Expires</span>
                <span>{(() => {
                  const d = new Date();
                  d.setDate(d.getDate() + parseInt(shareState.expiry, 10));
                  return d.toUTCString().replace("GMT", "UTC");
                })()}</span>
              </div>
              <div className="share-meta__row">
                <span className="muted">Auditor logs in?</span>
                <span>No · link is self-authenticating</span>
              </div>
            </div>
          </div>
        )}

        {shareState.stage === "sent" && (
          <div className="col gap-4">
            <div className="share-success">
              <div className="share-success__icon">{window.Icon.checkSimple({ size: 22 })}</div>
              <div>
                <div className="share-success__title">
                  <em style={{ fontStyle: "italic", fontFamily: "var(--font-display)", fontSize: 22 }}>Link delivered.</em>
                </div>
                <div className="share-success__sub">
                  Auditor at <strong>{shareState.email}</strong> can verify the chain offline using the CLI bundle. They have <strong>{shareState.expiry} days</strong> — we'll remind them at 24 hours before expiry.
                </div>
              </div>
            </div>
            <div className="share-meta">
              <div className="share-meta__row">
                <span className="muted">Recipient</span>
                <span>{shareState.email}</span>
              </div>
              <div className="share-meta__row">
                <span className="muted">Expires</span>
                <span>{(() => {
                  const d = new Date();
                  d.setDate(d.getDate() + parseInt(shareState.expiry, 10));
                  return d.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" }) + " · UTC";
                })()}</span>
              </div>
              <div className="share-meta__row">
                <span className="muted">Audit-log entry</span>
                <span className="mono text-xs">share.created · {new Date().toISOString().slice(0, 19)}Z</span>
              </div>
            </div>
          </div>
        )}
      </Modal>

      {/* Raw votes drawer */}
      <Drawer
        open={rawVotesOpen}
        onClose={() => setRawVotesOpen(false)}
        title="Raw judge votes"
        sub={`Claim ${claim.idx} of ${claim.total} · verbatim model output, signed.`}
        wide
      >
        <div className="col gap-4">
          {claim.judges.map((j) => (
            <div key={j.name} style={{ border: "1px solid var(--rule)", borderRadius: 8, padding: 16 }}>
              <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 8 }}>
                <strong>{j.name}</strong>
                <span className="mono text-xs muted">{j.model}</span>
                <span className="spacer" />
                <Verdict kind={j.verdict === "contradicted" ? "contra" : j.verdict} />
                <span className="text-sm mono tabular">conf {j.confidence.toFixed(2)}</span>
              </div>
              <div className="text-sm" style={{ color: "var(--ink-2)", lineHeight: 1.55, fontStyle: "italic", padding: "8px 12px", background: "var(--paper-alt)", borderRadius: 6 }}>
                "The claim is {j.verdict === "contradicted" ? "directly contradicted by" : "directly supported by"} the cited source span. Match confidence high; verbatim quote alignment {(j.confidence * 100).toFixed(1)}%."
              </div>
            </div>
          ))}
          <div style={{ padding: 14, background: "var(--brand-accent-soft)", border: "1px solid rgba(30, 166, 108, 0.3)", borderRadius: 8, fontSize: 12.5 }}>
            <strong>Signed bundle.</strong> Each judge's verbatim output is hashed and included in the evidence pack. Tamper-evident.
          </div>
        </div>
      </Drawer>

      {replayRunning && (
        <div className="modal-backdrop" style={{ zIndex: 1300 }}>
          <div className="modal">
            <div className="modal__body" style={{ textAlign: "center", padding: 32 }}>
              <div className="spinner-lg" />
              <h2 style={{ margin: "16px 0 8px", fontSize: 16, fontWeight: 600 }}>Re-running verification…</h2>
              <p className="text-sm muted">Same inputs · {SCENARIO.sources.length} sources resolved · ETA ~15s</p>
            </div>
          </div>
        </div>
      )}
    </>
  );
};

/* -------- Step detail (Region C — the focus) -------- */
const StepDetail = ({ stepId, claim, claims, claimIdx, setClaimIdx, isContradicted, isSandbox, onShowRaw }) => {
  if (stepId === "verify" && isSandbox) {
    return (
      <div className="step-detail">
        <div className="step-detail__head">
          <div>
            <h2>Verification <Badge tone="pending" size="lg" icon={window.Icon.clock({ size: 11 })}>Pending</Badge></h2>
            <p className="step-detail__sub">Awaiting sandbox availability — claim evidence will appear here once the verifier completes.</p>
          </div>
        </div>

        <div className="claim" style={{ display: "flex", flexDirection: "column", alignItems: "center", textAlign: "center", padding: 32, background: "var(--paper)" }}>
          <div style={{ width: 56, height: 56, borderRadius: 12, background: "var(--partial-soft)", color: "var(--partial)", display: "grid", placeItems: "center", marginBottom: 16 }}>
            {window.Icon.clock({ size: 24 })}
          </div>
          <h3 style={{ margin: 0, fontSize: 16, fontWeight: 600 }}>Sandbox queue position 3</h3>
          <p className="muted text-sm" style={{ margin: "6px 0 16px", maxWidth: 380 }}>
            We auto-retry every 30 seconds. The original LLM response is stored — no data was lost.
          </p>
          <div style={{ width: "100%", maxWidth: 360 }}>
            <div className="progress"><div className="progress__bar progress__bar--accent" style={{ width: "62%" }} /></div>
            <div className="row" style={{ justifyContent: "space-between", marginTop: 6, fontSize: 11.5, color: "var(--ink-3)" }}>
              <span>Next retry</span>
              <span className="mono">in 22s</span>
            </div>
          </div>
        </div>

        <div className="judges" style={{ marginTop: 16 }}>
          <div className="judges__head">
            <h4>What gets verified when sandbox returns</h4>
          </div>
          <div style={{ padding: 14, fontSize: 12.5, color: "var(--ink-2)", lineHeight: 1.6 }}>
            <div className="row gap-2" style={{ marginBottom: 6 }}>
              <span style={{ width: 16, height: 16, borderRadius: 4, background: "var(--paper-alt)", display: "grid", placeItems: "center", color: "var(--ink-4)" }}>{window.Icon.clock({ size: 10 })}</span>
              <span>3 extracted claims, awaiting multi-judge consensus</span>
            </div>
            <div className="row gap-2" style={{ marginBottom: 6 }}>
              <span style={{ width: 16, height: 16, borderRadius: 4, background: "var(--paper-alt)", display: "grid", placeItems: "center", color: "var(--ink-4)" }}>{window.Icon.clock({ size: 10 })}</span>
              <span>Source registry will be queried against {SCENARIO.sources.length} active sources</span>
            </div>
            <div className="row gap-2">
              <span style={{ width: 16, height: 16, borderRadius: 4, background: "var(--paper-alt)", display: "grid", placeItems: "center", color: "var(--ink-4)" }}>{window.Icon.clock({ size: 10 })}</span>
              <span>Evidence sealed and bulletin-anchored at completion</span>
            </div>
          </div>
        </div>
      </div>
    );
  }

  if (stepId === "verify") {
    return (
      <div className="step-detail">
        <div className="step-detail__head">
          <div>
            <h2>
              Verification
              <Verdict kind={claim.verdict === "contradicted" ? "contra" : claim.verdict} size="lg" />
            </h2>
            <p className="step-detail__sub">
              {isSandbox ? "Verification pending — sandbox queue position 3."
                : isContradicted ? "1 of 3 claims contradicted by your sources. 2 verified."
                : "3 of 3 claims verified by your source registry."}
            </p>
          </div>
          <div className="spacer" />
          <Button variant="ghost" size="sm" iconRight={window.Icon.chevronDown({ size: 12 })}>Export</Button>
        </div>

        {/* Claim navigator */}
        <div className="claim-nav">
          <Button variant="ghost" size="sm" disabled={claimIdx === 0} onClick={() => setClaimIdx((i) => Math.max(0, i - 1))}>
            {window.Icon.arrowLeft({ size: 12 })} Prev
          </Button>
          <div className="claim-nav__indicator">
            {claims.map((c, i) => (
              <span
                key={i}
                className={`claim-nav__dot claim-nav__dot--${c.verdict === "contradicted" ? "contra" : c.verdict} ${i === claimIdx ? "claim-nav__dot--active" : ""}`}
                style={{ color: c.verdict === "contradicted" ? "var(--contra)" : c.verdict === "partial" ? "var(--partial)" : "var(--verified)" }}
              />
            ))}
          </div>
          <span className="claim-nav__label">Claim <strong>{claim.idx}</strong> of <strong>{claim.total}</strong> · {claim.verdict === "contradicted" ? "contradicted" : "verified"}</span>
          <Button variant="ghost" size="sm" disabled={claimIdx === claims.length - 1} onClick={() => setClaimIdx((i) => Math.min(claims.length - 1, i + 1))}>
            Next {window.Icon.arrowRight({ size: 12 })}
          </Button>
        </div>

        {/* Claim card */}
        <div className="claim">
          <div className="row gap-2" style={{ marginBottom: 10, alignItems: "flex-start" }}>
            <span className="text-xs muted fw-600" style={{ letterSpacing: "0.06em", textTransform: "uppercase" }}>Extracted claim</span>
          </div>
          <p className={`claim__quote ${claim.verdict === "contradicted" ? "claim__quote--contradicted" : ""}`}>
            {claim.text}
          </p>

          {claim.sourceContradictionNote && (
            <div className="state-banner state-banner--error" style={{ marginBottom: 0, marginTop: 8, padding: "10px 12px" }}>
              <div className="state-banner__icon">{window.Icon.xCircle({ size: 12 })}</div>
              <div className="state-banner__sub" style={{ fontSize: 12.5 }}>{claim.sourceContradictionNote}</div>
            </div>
          )}

          <div style={{ marginTop: 16 }}>
            <div className="row gap-2" style={{ marginBottom: 8 }}>
              <span className="text-xs muted fw-600" style={{ letterSpacing: "0.06em", textTransform: "uppercase" }}>
                {claim.verdict === "contradicted" ? "Source contradicts this claim" : "Source supports this claim"}
              </span>
              <span className="spacer" />
              <span className="text-xs muted">{claim.sources.length} source{claim.sources.length === 1 ? "" : "s"}</span>
            </div>
            {claim.sources.map((src, i) => (
              <div key={i} className={`source-card ${claim.verdict === "contradicted" ? "source-card--contra" : ""}`}>
                <div className="source-card__radio" />
                <div className="source-card__body">
                  <div className="source-card__head">
                    {window.Icon.fileText({ size: 14 })}
                    <span>{src.name}</span>
                  </div>
                  <div className="source-card__span">{src.span}</div>
                  <div className="source-card__quote">{src.quote}</div>
                  <div className="source-card__score">
                    <span>Match score</span>
                    <div className="score-bar">
                      <div className="score-bar__fill" style={{ width: `${src.score}%` }} />
                    </div>
                    <span className="mono fw-600 tabular" style={{ color: "var(--ink-1)" }}>{src.score}%</span>
                  </div>
                </div>
              </div>
            ))}
          </div>
        </div>

        {/* Judges */}
        <div className="judges">
          <div className="judges__head">
            <h4>Multi-judge consensus</h4>
            <span className="spacer" />
            <Button variant="link" size="sm" onClick={onShowRaw} iconRight={window.Icon.external({ size: 11 })}>
              Show raw votes
            </Button>
          </div>
          <div className="judges__list">
            {claim.judges.map((j) => (
              <div key={j.name} className={`judge ${j.verdict === "contradicted" ? "judge--contra" : ""}`}>
                <div className="judge__name">
                  <span style={{ width: 6, height: 6, borderRadius: "50%", background: j.verdict === "contradicted" ? "var(--contra)" : "var(--brand-accent)" }} />
                  {j.name}
                </div>
                <div className="judge__model">{j.model}</div>
                <div className="row gap-2" style={{ marginTop: 6, justifyContent: "space-between" }}>
                  <Verdict kind={j.verdict === "contradicted" ? "contra" : j.verdict} />
                  <span className="mono text-xs tabular muted">conf {j.confidence.toFixed(2)}</span>
                </div>
                <div className="judge__bar">
                  <div className="judge__bar-fill" style={{ width: `${j.confidence * 100}%` }} />
                </div>
              </div>
            ))}
          </div>
          <div className={`judges__foot ${claim.verdict === "contradicted" ? "kappa--contra" : ""}`}>
            <div className={`kappa ${claim.verdict === "contradicted" ? "kappa--contra" : ""}`}>
              <span className="kappa__dot" />
              <span>Cohen's κ <strong className="mono">{claim.kappa.toFixed(2)}</strong></span>
              <span className="muted">· {claim.kappaLabel}</span>
            </div>
          </div>
        </div>
      </div>
    );
  }

  // Other steps — basic detail
  return <StepGenericDetail stepId={stepId} />;
};

const StepGenericDetail = ({ stepId }) => {
  const labels = {
    inbound: { title: "Inbound request", body: <InboundDetail /> },
    redaction: { title: "PHI redaction", body: <RedactionDetail /> },
    llm: { title: "LLM call", body: <LLMCallDetail /> },
    extraction: { title: "Claim extraction", body: <ExtractionDetail /> },
    seal: { title: "Evidence sealed", body: <div className="text-sm muted">See the Evidence seal panel below.</div> },
  };
  const d = labels[stepId] || labels.inbound;
  return (
    <div className="step-detail">
      <div className="step-detail__head">
        <div>
          <h2>{d.title}</h2>
        </div>
      </div>
      {d.body}
    </div>
  );
};

const InboundDetail = () => (
  <div className="col gap-4">
    <div>
      <div className="text-xs muted fw-600" style={{ letterSpacing: "0.06em", textTransform: "uppercase", marginBottom: 6 }}>Headers</div>
      <div className="preset-detail__rows">
        <PresetRow label="API key" value={<span className="mono">af_live_x3k…rt7yv</span>} />
        <PresetRow label="Idempotency key" value={<span className="mono">enc_29f8a1b…</span>} />
        <PresetRow label="User tag" value={<span className="mono">clinician-9847</span>} />
        <PresetRow label="Purpose" value={<span className="mono">discharge_summary</span>} />
      </div>
    </div>
    <div>
      <div className="text-xs muted fw-600" style={{ letterSpacing: "0.06em", textTransform: "uppercase", marginBottom: 6 }}>Request body</div>
      <pre className="install-code" style={{ background: "#0b1220", color: "#e7edf7" }}>
{`{
  "model": "gpt-4o-mini",
  "messages": [
    { "role": "system", "content": "You are a clinical summarization assistant…" },
    { "role": "user", "content": "[PATIENT_NAME_1] presents with new-onset HFrEF, LVEF 28%…" }
  ]
}`}
      </pre>
    </div>
  </div>
);

const RedactionDetail = () => (
  <div className="col gap-4">
    <div className="text-sm">4 HIPAA identifiers detected and substituted with deterministic surrogates. Original spans hashed; cannot be reversed without root key.</div>
    <table className="table">
      <thead>
        <tr>
          <th style={{ width: 80 }}>Type</th>
          <th>Original (hashed)</th>
          <th>Surrogate</th>
          <th>Span</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td><Badge tone="info">Name</Badge></td>
          <td className="mono text-sm">sha256:a3f…b21</td>
          <td className="mono text-sm">[PATIENT_NAME_1]</td>
          <td className="mono text-xs muted">chars 12-26</td>
        </tr>
        <tr>
          <td><Badge tone="info">DOB</Badge></td>
          <td className="mono text-sm">sha256:7e2…104</td>
          <td className="mono text-sm">[DOB_1]</td>
          <td className="mono text-xs muted">chars 51-61</td>
        </tr>
        <tr>
          <td><Badge tone="info">MRN</Badge></td>
          <td className="mono text-sm">sha256:9b4…aef</td>
          <td className="mono text-sm">[MRN_1]</td>
          <td className="mono text-xs muted">chars 84-93</td>
        </tr>
        <tr>
          <td><Badge tone="info">Provider</Badge></td>
          <td className="mono text-sm">sha256:c81…2dd</td>
          <td className="mono text-sm">[PROVIDER_1]</td>
          <td className="mono text-xs muted">chars 144-160</td>
        </tr>
      </tbody>
    </table>
  </div>
);

const LLMCallDetail = () => (
  <div className="preset-detail__rows">
    <PresetRow label="Provider · model" value={<span><strong>OpenAI</strong> · <span className="mono">gpt-4o-mini</span></span>} />
    <PresetRow label="Tokens in · out" value={<span className="mono tabular">842 · 392</span>} />
    <PresetRow label="Cost" value={<span className="mono tabular">$0.012</span>} />
    <PresetRow label="Time-to-first-token" value={<span className="mono tabular">242 ms</span>} />
    <PresetRow label="Time-to-complete" value={<span className="mono tabular">1,108 ms</span>} />
    <PresetRow label="Response hash" value={<HashChip value="0x7afe102d11c8…" short="0x7afe…11c8" />} />
  </div>
);

const ExtractionDetail = () => (
  <div className="col gap-3">
    <div className="text-sm">3 claims extracted from the response. Each is independently verifiable against the source registry.</div>
    {SCENARIO.claims.verified.map((c) => (
      <div key={c.idx} style={{ border: "1px solid var(--rule)", borderRadius: 8, padding: 14 }}>
        <div className="row gap-2" style={{ marginBottom: 6 }}>
          <span className="text-xs muted fw-600">CLAIM {c.idx}/{c.total}</span>
          <Verdict kind="verified" />
        </div>
        <div className="text-sm" style={{ lineHeight: 1.55 }}>{c.text}</div>
      </div>
    ))}
  </div>
);

/* -------- Evidence seal -------- */
const SealMark = ({ size = 88, pending }) => (
  <svg width={size} height={size} viewBox="0 0 88 88" style={{ display: "block", flexShrink: 0 }}>
    <defs>
      <path id="seal-curve-top" d="M 8 44 A 36 36 0 0 1 80 44" />
      <path id="seal-curve-bot" d="M 8 44 A 36 36 0 0 0 80 44" />
    </defs>
    {/* outer ring */}
    <circle cx="44" cy="44" r="42" fill="none" stroke={pending ? "#9a6418" : "#2f6e47"} strokeWidth="1" opacity="0.5" />
    {/* inner ring */}
    <circle cx="44" cy="44" r="36" fill="none" stroke={pending ? "#9a6418" : "#2f6e47"} strokeWidth="1.5" />
    {/* dotted middle */}
    <circle cx="44" cy="44" r="34" fill="none" stroke={pending ? "#9a6418" : "#2f6e47"} strokeWidth="0.5" strokeDasharray="1 2" opacity="0.6" />
    {/* curved text top */}
    <text fontFamily="Geist Mono, monospace" fontSize="6.5" fill={pending ? "#9a6418" : "#2f6e47"} letterSpacing="2">
      <textPath href="#seal-curve-top" startOffset="50%" textAnchor="middle">
        ATTESTIA · EVIDENCE · ED25519
      </textPath>
    </text>
    {/* curved text bottom */}
    <text fontFamily="Geist Mono, monospace" fontSize="6.5" fill={pending ? "#9a6418" : "#2f6e47"} letterSpacing="2">
      <textPath href="#seal-curve-bot" startOffset="50%" textAnchor="middle">
        · BLOCK 1247 · LEAF 23 ·
      </textPath>
    </text>
    {/* center mark */}
    <text x="44" y="42" textAnchor="middle" fontFamily="Instrument Serif, serif" fontStyle="italic" fontSize="22" fill={pending ? "#9a6418" : "#2f6e47"}>A</text>
    <line x1="32" y1="50" x2="56" y2="50" stroke={pending ? "#9a6418" : "#2f6e47"} strokeWidth="0.5" />
    <text x="44" y="60" textAnchor="middle" fontFamily="Geist Mono, monospace" fontSize="4.5" fill={pending ? "#9a6418" : "#2f6e47"} letterSpacing="0.5">
      {pending ? "PENDING" : "SEALED"}
    </text>
  </svg>
);

const EvidenceSeal = ({ isPending, isContradicted, auditor, onReplay, onShare }) => {
  const t = SCENARIO.trace;

  return (
    <div className="evidence-seal">
      <div className="evidence-seal__layout">
        <div className="evidence-seal__mark">
          <SealMark size={104} pending={isPending} />
        </div>
        <div className="evidence-seal__content">
          <div className="evidence-seal__head-row">
            <span className="evidence-seal__title">{isPending ? "Pending seal" : "Sealed evidence"}</span>
            <span className="evidence-seal__head-meta">
              {isPending ? "awaiting verifier" : "Ed25519 · daily public bulletin"}
            </span>
          </div>
          <div className="evidence-seal__rows">
            <div className="evidence-row">
              <span className="evidence-row__label">Evidence hash</span>
              <span className="evidence-row__value">
                <HashChip value={t.sealHash} short={t.sealHashShort} />
                {isPending && <Badge tone="pending">Generating</Badge>}
              </span>
            </div>
            <div className="evidence-row">
              <span className="evidence-row__label">Merkle position</span>
              <span className="evidence-row__value">
                <span className="mono">Block #{t.blockNumber.toLocaleString()}</span>
                <span className="muted text-xs">· leaf {t.leaf}</span>
              </span>
            </div>
            <div className="evidence-row">
              <span className="evidence-row__label">Daily bulletin</span>
              <span className="evidence-row__value">
                {!isPending ? (
                  <>
                    <Badge tone="verified" icon={window.Icon.checkSimple({ size: 11 })}>Verified {t.bulletinDate}</Badge>
                    <a href="#" onClick={(e) => e.preventDefault()} className="text-xs">github.com/attestia-ai/bulletins {window.Icon.external({ size: 10 })}</a>
                  </>
                ) : (
                  <Badge tone="neutral">Bulletin posts at 00:00 UTC</Badge>
                )}
              </span>
            </div>
            <div className="evidence-row">
              <span className="evidence-row__label">Algorithm</span>
              <span className="evidence-row__value">
                <span className="mono">Ed25519</span>
                <span className="muted text-xs">· root key fp <span className="mono">5e8f…b21a</span></span>
              </span>
            </div>
          </div>
        </div>
      </div>

      <div className="evidence-seal__actions">
        {!auditor && (
          <>
            <Button variant="primary" size="sm" icon={window.Icon.replay({ size: 14 })} onClick={onReplay} disabled={isPending}>
              Replay this call
            </Button>
            <Button variant="secondary" size="sm" icon={window.Icon.share({ size: 14 })} onClick={onShare} disabled={isPending}>
              Share with auditor
            </Button>
            <Button variant="ghost" size="sm" icon={window.Icon.download({ size: 14 })} disabled={isPending}>
              Download evidence pack
            </Button>
          </>
        )}
        {auditor && (
          <>
            <Button variant="primary" size="sm" icon={window.Icon.download({ size: 14 })}>Download bundle (.zip)</Button>
            <Button variant="secondary" size="sm" icon={window.Icon.external({ size: 14 })}>Open verify CLI guide</Button>
          </>
        )}
      </div>
    </div>
  );
};

window.TraceReplay = TraceReplay;
