/* global React, DemixViz */
const { Button, Card, Chip, ClaimCeiling, GradientText, Field, Input } = window.OregonCoastAIDesignSystem_e04d97;

/* Soft client-side gate — not security. Lets the user hand a key to specific
 * decision-makers. Accepted keys are intentionally simple; change DEMO_KEYS or
 * wire the `accessKey` tweak as needed. */
const DEMO_KEYS = ["tonix-demo-01", "demix26"];

function GateScreen({ onUnlock }) {
  const Wrap = window.OCAWrap;
  const [val, setVal] = React.useState("");
  const [err, setErr] = React.useState(false);
  const submit = (e) => {
    e.preventDefault();
    if (DEMO_KEYS.includes(val.trim().toLowerCase())) { localStorage.setItem("ie_demo_unlocked", "1"); onUnlock(); }
    else setErr(true);
  };
  return (
    <section style={{ minHeight: "62vh", display: "flex", alignItems: "center", padding: "60px 0" }}>
      <Wrap>
        <div style={{ maxWidth: "460px", margin: "0 auto", textAlign: "center" }}>
          <div style={{ fontFamily: "var(--font-mono)", fontSize: "12px", letterSpacing: "0.14em", textTransform: "uppercase", color: "var(--text-accent)", marginBottom: "12px" }}>Gated · by invitation</div>
          <h2 style={{ fontSize: "clamp(26px,4vw,38px)", lineHeight: 1.14, margin: "0 0 14px", fontWeight: 700, color: "var(--text-strong)" }}>
            The interactive <GradientText>de-mixing demo</GradientText>
          </h2>
          <p style={{ color: "var(--text-body)", fontSize: "16px", lineHeight: 1.6, margin: "0 0 26px" }}>
            A live, worked case built for named decision-makers. Enter the access key from your invitation to continue.
          </p>
          <form onSubmit={submit} style={{ display: "flex", flexDirection: "column", gap: "12px", alignItems: "stretch" }}>
            <Input name="key" placeholder="Access key" value={val} invalid={err}
              onChange={(e) => { setVal(e.target.value); setErr(false); }}
              style={{ textAlign: "center", fontFamily: "var(--font-mono)", letterSpacing: "0.1em" }} />
            <Button type="submit" size="lg">Unlock demo</Button>
          </form>
          {err ? <p style={{ fontFamily: "var(--font-mono)", fontSize: "11px", color: "var(--danger)", marginTop: "12px" }}>Key not recognized. Check your invitation.</p>
            : <div style={{ marginTop: "16px" }}><ClaimCeiling>Soft access gate for previewing — not a security boundary. No data leaves your browser.</ClaimCeiling></div>}
        </div>
      </Wrap>
    </section>
  );
}

// effect-size bar
function EffectBar({ label, d, color, max = 1.0, note }) {
  return (
    <div style={{ marginBottom: "14px" }}>
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", marginBottom: "5px" }}>
        <span style={{ fontSize: "13px", color: "var(--text-strong)", fontWeight: 500 }}>{label}</span>
        <span style={{ fontFamily: "var(--font-mono)", fontSize: "13px", color, fontVariantNumeric: "tabular-nums" }}>d = {d.toFixed(2)}</span>
      </div>
      <div style={{ height: "8px", background: "var(--surface-page)", borderRadius: "999px", overflow: "hidden", border: "1px solid var(--border-line)" }}>
        <div style={{ height: "100%", width: `${Math.min(100, (d / max) * 100)}%`, background: color, borderRadius: "999px", transition: "width 120ms linear" }} />
      </div>
      {note ? <div style={{ fontFamily: "var(--font-mono)", fontSize: "10px", color: "var(--text-muted)", marginTop: "4px" }}>{note}</div> : null}
    </div>
  );
}

// representative subject record inspector
function SubjectInspector({ t, recordType }) {
  // synthesize 5 trace-normalized eigenvalues that sharpen (lower entropy) as t→1
  const base = recordType === "abstain"
    ? [0.27, 0.24, 0.21, 0.16, 0.12]
    : [0.30, 0.25, 0.20, 0.15, 0.10];
  const peaked = recordType === "abstain"
    ? [0.30, 0.26, 0.20, 0.14, 0.10]   // abstain barely sharpens — stays high-entropy
    : [0.62, 0.18, 0.10, 0.06, 0.04];
  const ev = base.map((b, i) => b + (peaked[i] - b) * t);
  const sum = ev.reduce((a, b) => a + b, 0);
  const p = ev.map((e) => e / sum);
  const H = -p.reduce((a, x) => a + (x > 0 ? x * Math.log(x) : 0), 0);
  const Hmax = Math.log(5);
  const routed = recordType === "abstain" ? "ABSTAIN" : (t > 0.55 ? "Class A · responder-enriched" : "resolving…");
  const flagColor = recordType === "abstain" ? "var(--warning)" : (t > 0.55 ? "var(--success)" : "var(--text-muted)");
  return (
    <div style={{ background: "var(--surface-inset)", border: "1px solid var(--border-line)", borderRadius: "var(--radius-lg)", padding: "20px" }}>
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "14px" }}>
        <span style={{ fontFamily: "var(--font-mono)", fontSize: "11px", color: "var(--text-muted)", letterSpacing: "0.06em", textTransform: "uppercase" }}>Record inspector · {recordType === "abstain" ? "REC-0488" : "REC-0207"}</span>
        <span style={{ fontFamily: "var(--font-mono)", fontSize: "11px", color: flagColor }}>{routed}</span>
      </div>
      <div style={{ fontFamily: "var(--font-mono)", fontSize: "10.5px", color: "var(--text-muted)", marginBottom: "8px" }}>trace-normalized eigenvalue spectrum ρ</div>
      <div style={{ display: "flex", alignItems: "flex-end", gap: "8px", height: "84px", marginBottom: "14px" }}>
        {p.map((v, i) => (
          <div key={i} style={{ flex: 1, display: "flex", flexDirection: "column", justifyContent: "flex-end", alignItems: "center", gap: "5px" }}>
            <div style={{ width: "100%", height: `${v * 110}px`, background: recordType === "abstain" ? "var(--warning)" : "var(--accent)", opacity: 0.35 + v, borderRadius: "3px 3px 0 0", transition: "height 120ms linear" }} />
            <span style={{ fontFamily: "var(--font-mono)", fontSize: "9px", color: "var(--text-muted)" }}>λ{i + 1}</span>
          </div>
        ))}
      </div>
      <div style={{ display: "flex", justifyContent: "space-between", borderTop: "1px solid var(--border-line)", paddingTop: "12px" }}>
        <window.OCAMetric label="Spectral entropy H_S" value={H.toFixed(3)} unit="nats" sub={`of H_max ${Hmax.toFixed(2)}`} color={recordType === "abstain" ? "var(--warning)" : "var(--text-accent)"} />
        <window.OCAMetric label="Gate" value={recordType === "abstain" ? "fail" : "pass"} sub={recordType === "abstain" ? "→ abstain route" : "PSD · trace>0"} color={recordType === "abstain" ? "var(--warning)" : "var(--success)"} />
      </div>
    </div>
  );
}

function DemoApp({ onNav }) {
  const Wrap = window.OCAWrap, Section = window.OCASection, Kicker = window.OCAKicker, SH = window.OCASH, VizLegend = window.OCAVizLegend, Pipeline = window.OCAPipeline;
  const [t, setT] = React.useState(0);
  const [playing, setPlaying] = React.useState(false);
  const [vizStyle, setVizStyle] = React.useState("ellipsoid");
  const [showAbstain, setShowAbstain] = React.useState(true);
  const [showSpec, setShowSpec] = React.useState(false);
  const [recordType, setRecordType] = React.useState("responder");
  const [r, setR] = React.useState(null);
  const rafRef = React.useRef(0);

  // play animation 0→1 (timer-driven so it runs even when not foregrounded)
  React.useEffect(() => {
    if (!playing) return;
    const start = performance.now(); const dur = 2600;
    const iv = setInterval(() => {
      const k = Math.min(1, (performance.now() - start) / dur);
      setT(k);
      if (k >= 1) { clearInterval(iv); setPlaying(false); }
    }, 33);
    return () => clearInterval(iv);
  }, [playing]);

  const ittD = 0.31;
  const respD = 0.31 + t * 0.42;
  const nonD = 0.31 - t * 0.21;

  const ctrlBtn = (active, label, onClick) => (
    <button onClick={onClick} style={{
      fontFamily: "var(--font-mono)", fontSize: "11px", padding: "7px 12px", cursor: "pointer",
      borderRadius: "var(--radius-sm)", border: `1px solid ${active ? "var(--accent)" : "var(--border-line)"}`,
      background: active ? "var(--tint-accent)" : "transparent", color: active ? "var(--text-accent)" : "var(--text-muted)",
      transition: "all 120ms ease",
    }}>{label}</button>
  );

  return (
    <div>
      {/* disclaimer banner */}
      <div style={{ background: "var(--tint-warning)", borderBottom: "1px solid rgba(255,180,84,0.35)" }}>
        <Wrap wide>
          <p style={{ fontFamily: "var(--font-mono)", fontSize: "11px", color: "var(--warning)", padding: "10px 0", margin: 0, lineHeight: 1.5 }}>
            ILLUSTRATIVE SIMULATION · synthetic cohort · NOT Tonix or Tonmya trial data. Public facts are cited as public record; the worked case demonstrates method behavior only and asserts nothing about any real product or study.
          </p>
        </Wrap>
      </div>

      <header style={{ padding: "44px 0 32px", borderBottom: "1px solid var(--border-line)" }}>
        <Wrap wide>
          <div style={{ fontFamily: "var(--font-mono)", fontSize: "12px", letterSpacing: "0.14em", textTransform: "uppercase", color: "var(--text-accent)" }}>Worked case · gated demo</div>
          <h2 style={{ fontSize: "clamp(26px,4vw,42px)", lineHeight: 1.12, margin: "14px 0 14px", fontWeight: 700, color: "var(--text-strong)", maxWidth: "24ch" }}>
            De-mixing a fibromyalgia Phase 3 population — the <GradientText>Tonmya</GradientText> case
          </h2>
          <p style={{ fontSize: "17px", color: "var(--text-body)", maxWidth: "70ch", margin: 0, lineHeight: 1.62 }}>
            Tonix Pharmaceuticals' Tonmya (TNX-102 SL, sublingual cyclobenzaprine) was approved by the FDA on August 15, 2025 — the first new fibromyalgia therapy in over 15 years, supported by Phase 3 trials enrolling roughly one thousand patients. Those trials, like all fibromyalgia trials, randomized a clinically labeled population that is biologically heterogeneous. Below: what a registered de-mix of such an ITT population looks like, on a synthetic cohort.
          </p>
        </Wrap>
      </header>

      {/* main interactive */}
      <Section wide>
        <div className="demo-grid" style={{ display: "grid", gridTemplateColumns: "1.35fr 1fr", gap: "24px", alignItems: "start" }}>
          {/* left: viz + controls */}
          <div style={{ background: "var(--bg-panel-gradient)", border: "1px solid var(--border-line)", borderRadius: "var(--radius-lg)", padding: "18px" }}>
            <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "12px", flexWrap: "wrap", gap: "8px" }}>
              <span style={{ fontFamily: "var(--font-mono)", fontSize: "11px", color: "var(--text-muted)", letterSpacing: "0.06em" }}>SYNTHETIC ITT COHORT · N=300</span>
              <div style={{ display: "flex", gap: "6px" }}>
                {ctrlBtn(vizStyle === "ellipsoid", "ellipsoid", () => setVizStyle("ellipsoid"))}
                {ctrlBtn(vizStyle === "constellation", "kNN panels", () => setVizStyle("constellation"))}
                {ctrlBtn(vizStyle === "field", "entropy field", () => setVizStyle("field"))}
              </div>
            </div>
            <DemixViz vizStyle={vizStyle} target={t} auto={false} showAbstain={showAbstain} showSpecificity={showSpec} height={360} onReadout={setR} seed={11} />
            <div style={{ marginTop: "12px" }}><VizLegend compact /></div>

            {/* de-mix control */}
            <div style={{ marginTop: "18px", paddingTop: "16px", borderTop: "1px solid var(--border-line)" }}>
              <div style={{ display: "flex", alignItems: "center", gap: "12px", flexWrap: "wrap" }}>
                <Button size="sm" onClick={() => { setT(0); setPlaying(true); }}>▶ Run de-mix</Button>
                {ctrlBtn(false, "reset", () => { setPlaying(false); setT(0); })}
                <div style={{ flex: 1, minWidth: "160px", display: "flex", alignItems: "center", gap: "10px" }}>
                  <span style={{ fontFamily: "var(--font-mono)", fontSize: "10px", color: "var(--text-muted)" }}>mixed</span>
                  <input className="demix-range" type="range" min="0" max="100" value={Math.round(t * 100)}
                    onChange={(e) => { setPlaying(false); setT(Number(e.target.value) / 100); }} style={{ flex: 1 }} />
                  <span style={{ fontFamily: "var(--font-mono)", fontSize: "10px", color: "var(--text-accent)" }}>de-mixed</span>
                </div>
              </div>
              <div style={{ display: "flex", gap: "8px", marginTop: "12px", flexWrap: "wrap" }}>
                {ctrlBtn(showAbstain, showAbstain ? "abstain ●" : "abstain ○", () => setShowAbstain((v) => !v))}
                {ctrlBtn(showSpec, showSpec ? "specificity ●" : "specificity ○", () => setShowSpec((v) => !v))}
              </div>
            </div>
          </div>

          {/* right: readouts */}
          <div style={{ display: "flex", flexDirection: "column", gap: "16px" }}>
            <div style={{ background: "var(--surface-card)", border: "1px solid var(--border-line)", borderRadius: "var(--radius-lg)", padding: "20px" }}>
              <div style={{ fontFamily: "var(--font-mono)", fontSize: "11px", color: "var(--text-muted)", letterSpacing: "0.06em", textTransform: "uppercase", marginBottom: "14px" }}>Live cohort readout</div>
              <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "18px 12px" }}>
                <window.OCAMetric label="Apparent classes" value={r ? r.classes : 1} sub={r && r.demixed ? "resolved" : "resolving…"} color={r && r.demixed ? "var(--text-accent)" : "var(--text-strong)"} />
                <window.OCAMetric label="Mean H_S" value={(r ? r.entropy : 0.69).toFixed(3)} unit="nats" />
                <window.OCAMetric label="Abstained" value={r ? r.abstain : 0} sub="→ review" color="var(--warning)" />
                <window.OCAMetric label="De-mix" value={`${Math.round(t * 100)}%`} sub="workflow progress" />
              </div>
            </div>

            <div style={{ background: "var(--surface-card)", border: "1px solid var(--border-line)", borderRadius: "var(--radius-lg)", padding: "20px" }}>
              <div style={{ fontFamily: "var(--font-mono)", fontSize: "11px", color: "var(--text-muted)", letterSpacing: "0.06em", textTransform: "uppercase", marginBottom: "16px" }}>Apparent treatment effect (illustrative)</div>
              <EffectBar label="Pooled ITT population" d={ittD} color="var(--text-muted)" note="what a whole-cohort analysis sees" />
              <EffectBar label="Class A — responder-enriched" d={respD} color="var(--success)" note="effect concentrates as the cohort resolves" />
              <EffectBar label="Class B/C — non-responder" d={Math.max(0.02, nonD)} color="var(--accent-3)" note="dilution source, separated out" />
              <div style={{ margin: "6px 0 0" }}><ClaimCeiling>Synthetic effect sizes · illustrate dilution, not a Tonmya result.</ClaimCeiling></div>
            </div>
          </div>
        </div>
      </Section>

      {/* record inspector */}
      <Section wide>
        <Kicker>Per-record view</Kicker>
        <SH>One subject, gated</SH>
        <p style={{ color: "var(--text-body)", maxWidth: "62ch", margin: "0 0 18px", fontSize: "15px", lineHeight: 1.6 }}>
          Every record carries its own local covariance operator. As the cohort de-mixes, a responder-class record's spectrum sharpens toward a low-entropy signature; a boundary record fails its gate and abstains rather than being forced into a class.
        </p>
        <div className="cards-2" style={{ alignItems: "start" }}>
          <div>
            <div style={{ display: "flex", gap: "8px", marginBottom: "14px" }}>
              {ctrlBtn(recordType === "responder", "responder record", () => setRecordType("responder"))}
              {ctrlBtn(recordType === "abstain", "boundary record", () => setRecordType("abstain"))}
            </div>
            <SubjectInspector t={t} recordType={recordType} />
          </div>
          <div style={{ background: "var(--surface-inset)", border: "1px solid var(--border-line)", borderRadius: "var(--radius-lg)", padding: "20px" }}>
            <div style={{ fontFamily: "var(--font-mono)", fontSize: "11px", color: "var(--text-muted)", letterSpacing: "0.06em", textTransform: "uppercase", marginBottom: "14px" }}>Routing pipeline</div>
            <Pipeline steps={["record", "local cov Cⱼ", "PSD gate", "ρⱼ = Cⱼ/Tr", "H_S", "HC reference", recordType === "abstain" ? "ABSTAIN" : "Class A"]} />
            <p style={{ color: "var(--text-muted)", fontSize: "13px", lineHeight: 1.6, margin: "16px 0 0" }}>
              The gate is a hard numerical predicate — real symmetry, positive-semidefiniteness, strictly positive trace. A record that fails is not classified; it is routed to specialist review. Abstention is a feature, not an error.
            </p>
          </div>
        </div>
      </Section>

      {/* receipt + CTA */}
      <Section wide>
        <div className="cards-2" style={{ alignItems: "start", gridTemplateColumns: "1fr 1fr" }}>
          <div style={{ background: "var(--surface-inset)", border: "1px solid var(--border-line)", borderRadius: "var(--radius-lg)", padding: "20px", fontFamily: "var(--font-mono)", fontSize: "12px", lineHeight: 1.7, color: "var(--text-strong)" }}>
            <div style={{ color: "var(--text-muted)", marginBottom: "10px", letterSpacing: "0.06em" }}>// run-receipt.json (this session)</div>
            <pre style={{ margin: 0, whiteSpace: "pre-wrap" }}>{`{
  "experiment_id": "EXP-IE-FM-DEMO",
  "cohort": "synthetic-itt-300",
  "status": "hypothesis-generating",
  "classes_resolved": ${r ? r.classes : 1},
  "mean_H_S": ${(r ? r.entropy : 0.69).toFixed(3)},
  "responder_class_d": ${respD.toFixed(2)},
  "abstained": ${r ? r.abstain : 0},
  "claim_ceiling": "methods-only · illustrative",
  "asserts_about_tonmya": false
}`}</pre>
          </div>
          <div style={{ background: "var(--bg-panel-gradient)", border: "1px solid var(--border-line)", borderRadius: "var(--radius-lg)", padding: "24px", display: "flex", flexDirection: "column", justifyContent: "center" }}>
            <h3 style={{ margin: "0 0 12px", fontSize: "22px", color: "var(--text-strong)", fontWeight: 700, lineHeight: 1.2 }}>Run this on a real cohort</h3>
            <p style={{ color: "var(--text-strong)", fontSize: "15px", lineHeight: 1.6, margin: "0 0 20px" }}>
              A sponsored engagement applies the registered workflow to your data under NDA, returning a versioned results package — structured JSON, human report, and checksum — with an immutable experiment ID.
            </p>
            <div style={{ display: "flex", gap: "12px", flexWrap: "wrap" }}>
              <Button onClick={() => onNav("intake")}>Discuss a sponsored engagement</Button>
              <Button variant="ghost" onClick={() => onNav("service")}>Service lines</Button>
            </div>
          </div>
        </div>
      </Section>
    </div>
  );
}

function DemoScreen({ onNav }) {
  const [unlocked, setUnlocked] = React.useState(() => localStorage.getItem("ie_demo_unlocked") === "1");
  return unlocked ? <DemoApp onNav={onNav} /> : <GateScreen onUnlock={() => setUnlocked(true)} />;
}

window.DemoScreen = DemoScreen;
