// explainer-scenes.jsx, the SciPHR animated explainer.
// A ~34s narrative: the secret → generate & back up (on device) → anchor to ledger →
// authenticate & sign locally → recovery → resolution. Brand: black, mono, amber accent.
// Composes Sprites inside a <Stage> (see explainer.html).

const EX_MONO = 'Menlo, ui-monospace, SFMono-Regular, "JetBrains Mono", Consolas, "Liberation Mono", "Courier New", monospace';
const EX = { black: '#000', white: '#fff', gray: '#E0E0E0', dark: '#808080', darker: '#404040', amber: '#FFB800' };
const W = 1280, H = 720;

// ── shared primitives ───────────────────────────────────────────────────────
function Box({ x, y, w, h, label, sub, accent, opacity = 1, scale = 1, active }) {
  return (
    <div style={{
      position: 'absolute', left: x, top: y, width: w, height: h,
      transform: `translate(-50%,-50%) scale(${scale})`,
      border: `2px solid ${active ? EX.amber : accent ? EX.amber : EX.dark}`,
      background: active ? 'rgba(255,184,0,0.10)' : 'rgba(255,255,255,0.02)',
      boxShadow: active ? `0 0 24px 0 rgba(255,184,0,0.35)` : 'none',
      borderRadius: 4, opacity, display: 'flex', flexDirection: 'column',
      alignItems: 'center', justifyContent: 'center', gap: 6, textAlign: 'center',
      transition: 'border-color 200ms, background 200ms, box-shadow 200ms',
    }}>
      <span style={{ fontFamily: EX_MONO, fontSize: 22, fontWeight: 600, color: active ? EX.amber : EX.white }}>{label}</span>
      {sub && <span style={{ fontFamily: EX_MONO, fontSize: 13, letterSpacing: '0.16em', textTransform: 'uppercase', color: EX.dark }}>{sub}</span>}
    </div>
  );
}

function Connector({ x1, y1, x2, y2, fill = 0, op = 1 }) {
  const len = Math.hypot(x2 - x1, y2 - y1);
  const ang = Math.atan2(y2 - y1, x2 - x1) * 180 / Math.PI;
  return (
    <div style={{ position: 'absolute', left: x1, top: y1, width: len, height: 2, opacity: op,
      transform: `rotate(${ang}deg)`, transformOrigin: '0 50%', background: EX.darker }}>
      <div style={{ position: 'absolute', inset: 0, width: `${fill * 100}%`, background: EX.amber }} />
    </div>
  );
}

function SceneCaption({ eyebrow, line, op = 1, sub }) {
  return (
    <div style={{ position: 'absolute', left: 90, bottom: 70, opacity: op, maxWidth: 1100 }}>
      <div style={{ fontFamily: EX_MONO, fontSize: 15, letterSpacing: '0.4em', textTransform: 'uppercase', color: EX.amber, marginBottom: 16 }}>{eyebrow}</div>
      <div style={{ fontFamily: EX_MONO, fontSize: 46, fontWeight: 600, color: EX.white, lineHeight: 1.12, letterSpacing: '-0.01em' }}>{line}</div>
      {sub && <div style={{ fontFamily: EX_MONO, fontSize: 19, color: EX.dark, marginTop: 16, lineHeight: 1.5 }}>{sub}</div>}
    </div>
  );
}

const fadeInOut = (lt, dur, fade = 0.5) => {
  if (lt < fade) return clamp(lt / fade, 0, 1);
  if (lt > dur - fade) return clamp((dur - lt) / fade, 0, 1);
  return 1;
};

// ── persistent chrome: eyebrow tag + progress rail + caret ──────────────────
function Chrome() {
  const t = useTime();
  const total = 34;
  return (
    <React.Fragment>
      <div style={{ position: 'absolute', top: 44, left: 90, display: 'flex', alignItems: 'center', gap: 14 }}>
        <img src="assets/sciphr-logo.png" alt="" style={{ width: 26, height: 26, opacity: 0.7 }} />
        <span style={{ fontFamily: EX_MONO, fontSize: 14, letterSpacing: '0.34em', textTransform: 'uppercase', color: EX.white }}>SciPHR</span>
        <span style={{ fontFamily: EX_MONO, fontSize: 12, letterSpacing: '0.3em', textTransform: 'uppercase', color: EX.dark }}>/ dKMS</span>
      </div>
      <div style={{ position: 'absolute', top: 50, right: 90, fontFamily: EX_MONO, fontSize: 12, letterSpacing: '0.3em', textTransform: 'uppercase', color: EX.dark }}>
        Network <span style={{ color: EX.amber }}>TESTNET</span>
      </div>
      <div style={{ position: 'absolute', left: 90, right: 90, bottom: 44, height: 2, background: EX.darker }}>
        <div style={{ height: '100%', width: `${(t / total) * 100}%`, background: EX.amber, transition: 'width 80ms linear' }} />
      </div>
    </React.Fragment>
  );
}

// ── Scene 1, Hook ───────────────────────────────────────────────────────────
function S1Hook() {
  return (
    <Sprite start={0} end={4.6}>{({ localTime }) => {
      const op = fadeInOut(localTime, 4.6, 0.6);
      const mk = animate({ from: 0.7, to: 1, start: 0, end: 0.8, ease: Easing.easeOutCubic })(localTime);
      return (
        <div style={{ position: 'absolute', inset: 0, opacity: op, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 22 }}>
          <img src="assets/sciphr-logo.png" alt="" style={{ width: 96, height: 96, opacity: 0.85, transform: `scale(${mk})` }} />
          <div style={{ fontFamily: EX_MONO, fontSize: 64, fontWeight: 600, color: EX.white, letterSpacing: '-0.02em' }}>You hold the keys.</div>
          <div style={{ fontFamily: EX_MONO, fontSize: 20, letterSpacing: '0.3em', textTransform: 'uppercase', color: EX.dark }}>The first decentralized Key Management System</div>
        </div>
      );
    }}</Sprite>
  );
}

// ── Scene 2, The secret ─────────────────────────────────────────────────────
function S2Secret() {
  return (
    <Sprite start={4.6} end={9.2}>{({ localTime }) => {
      const op = fadeInOut(localTime, 4.6, 0.55);
      const pulse = 1 + 0.02 * Math.sin(localTime * 3);
      return (
        <div style={{ position: 'absolute', inset: 0, opacity: op }}>
          <Box x={W/2} y={300} w={300} h={150} label="SEED" sub="wallet secret" scale={pulse} accent />
          <SceneCaption eyebrow="01 · The secret" line={<span>Every wallet has one secret.</span>}
            sub="Lose it, leak it, or hand it to a custodian, and it's no longer yours." op={fadeInOut(localTime, 4.6, 0.8)} />
        </div>
      );
    }}</Sprite>
  );
}

// ── Scene 3, Generate & back up (on device) ─────────────────────────────────
function S3Encrypt() {
  return (
    <Sprite start={9.2} end={16.4}>{({ localTime }) => {
      const op = fadeInOut(localTime, 7.2, 0.55);
      const cy = 250;
      const xs = [180, 470, 760, 1050];
      const nodes = [
        { label: 'On-device key', sub: 'Ed25519 · Keychain', at: 0.4 },
        { label: 'Backup key', sub: 'AES-256-GCM', at: 1.6 },
        { label: '3-way wrap', sub: 'SE · iCloud · code', at: 2.8 }
      ];
      return (
        <div style={{ position: 'absolute', inset: 0, opacity: op }}>
          {nodes.map((n, i) => (
            <Box key={i} x={xs[i]} y={cy} w={236} h={96} label={n.label} sub={n.sub}
              opacity={animate({ from: 0, to: 1, start: n.at, end: n.at + 0.4 })(localTime)}
              active={localTime > n.at && localTime < n.at + 1.5} />
          ))}
          {nodes.slice(1).map((n, i) => (
            <Connector key={i} x1={xs[i] + 118} y1={cy} x2={xs[i + 1] - 118} y2={cy}
              fill={animate({ from: 0, to: 1, start: nodes[i].at + 0.3, end: nodes[i + 1].at })(localTime)}
              op={animate({ from: 0, to: 1, start: nodes[i].at, end: nodes[i].at + 0.3 })(localTime)} />
          ))}
          <Connector x1={xs[2] + 118} y1={cy} x2={xs[3] - 110} y2={cy}
            fill={animate({ from: 0, to: 1, start: 3.4, end: 4.2 })(localTime)}
            op={animate({ from: 0, to: 1, start: 3.2, end: 3.5 })(localTime)} />
          <Box x={xs[3]} y={cy} w={220} h={96} label="Envelope" sub="→ IPFS · NFT anchor" accent
            active={localTime > 4.2} opacity={animate({ from: 0, to: 1, start: 3.6, end: 4.2 })(localTime)} />
          <SceneCaption eyebrow="02 · Back up" line={<span>Made on your device. Backed up for no one else.</span>}
            sub="Your keys are generated on the phone; the master key is sealed with AES-256-GCM and the backup key is wrapped to your Enclave, iCloud, and recovery code. The envelope is anchored by the NFT." op={fadeInOut(localTime, 7.2, 0.8)} />
        </div>
      );
    }}</Sprite>
  );
}

// ── Scene 4, Mint to ledger ─────────────────────────────────────────────────
function S4Mint() {
  return (
    <Sprite start={16.4} end={22.4}>{({ localTime }) => {
      const op = fadeInOut(localTime, 6.0, 0.55);
      // sciphrtext flies from left into NFT card
      const fly = animate({ from: 0, to: 1, start: 0.6, end: 2.0, ease: Easing.easeInOutCubic })(localTime);
      const tx = 200 + fly * (W/2 - 200);
      const ty = 300;
      const landed = localTime > 2.0;
      const cardScale = landed ? 1 + 0.03*Math.sin((localTime-2)*2.5) : 0.9;
      return (
        <div style={{ position: 'absolute', inset: 0, opacity: op }}>
          {/* NFT card */}
          <div style={{ position: 'absolute', left: W/2, top: ty, transform: `translate(-50%,-50%) scale(${cardScale})`,
            width: 360, height: 230, border: `2px solid ${EX.amber}`, borderRightWidth: 3, borderBottomWidth: 3,
            boxShadow: `6px 6px 0 0 rgba(255,184,0,0.3)`, borderRadius: 4, background: '#000',
            opacity: animate({from:0,to:1,start:0,end:0.6})(localTime), padding: 22 }}>
            <div style={{ fontFamily: EX_MONO, fontSize: 16, letterSpacing: '0.24em', textTransform: 'uppercase', color: EX.amber }}>xCIPHR NFT</div>
            <div style={{ fontFamily: EX_MONO, fontSize: 12, letterSpacing: '0.2em', textTransform: 'uppercase', color: EX.dark, marginTop: 8 }}>Taxon 3 · XRP Ledger</div>
            <div style={{ borderTop: `1px solid ${EX.darker}`, margin: '16px 0' }} />
            <div style={{ fontFamily: EX_MONO, fontSize: 14, color: landed ? EX.white : EX.darker, lineHeight: 1.8 }}>
              <div>uri: {landed ? <span style={{color:EX.amber}}>sciphr:v5:Qm…</span> : '…'}</div>
              <div>envelope: IPFS · sealed</div>
              <div>did: did:xrpl:testnet:rhVDMM…</div>
            </div>
          </div>
          {/* flying sciphrtext */}
          {!landed && <div style={{ position: 'absolute', left: tx, top: ty, transform: 'translate(-50%,-50%)',
            fontFamily: EX_MONO, fontSize: 14, color: EX.amber, border: `1px solid ${EX.amber}`, padding: '8px 12px', borderRadius: 4, background:'#000' }}>› envelope</div>}
          <SceneCaption eyebrow="03 · Anchor" line={<span>Stored in the open. Useless to everyone else.</span>}
            sub="The envelope is pinned to content-addressed storage and the NFT anchors a provenance pointer to it. Immutable, portable, and unreadable without your device, iCloud, or recovery code." op={fadeInOut(localTime,6.0,0.8)} />
        </div>
      );
    }}</Sprite>
  );
}

// ── Scene 5, Authenticate & sign ────────────────────────────────────────────
function S5Sign() {
  return (
    <Sprite start={22.4} end={30.2}>{({ localTime }) => {
      const op = fadeInOut(localTime, 7.8, 0.55);
      const steps = [
        { at: 0.4, label: 'Face ID', sub: 'unlock' },
        { at: 1.8, label: 'Verify fields', sub: 'WYSIWYS' },
        { at: 3.2, label: 'Sign', sub: 'Ed25519 · on device' },
        { at: 4.6, label: 'Broadcast', sub: 'backend' },
        { at: 6.0, label: 'Settled', sub: 'XRPL' },
      ];
      const xs = [180, 405, 640, 875, 1100];
      const cy = 290;
      return (
        <div style={{ position: 'absolute', inset: 0, opacity: op }}>
          {steps.map((s, i) => {
            const appear = animate({ from: 0, to: 1, start: s.at, end: s.at + 0.4 })(localTime);
            const active = localTime > s.at && localTime < (steps[i+1] ? steps[i+1].at + 0.3 : 99);
            return <Box key={i} x={xs[i]} y={cy} w={195} h={96} label={s.label} sub={s.sub} opacity={appear} active={active && localTime < s.at + 1.4} accent={i===4 && localTime>6} />;
          })}
          {steps.slice(1).map((s, i) => (
            <Connector key={i} x1={xs[i]+98} y1={cy} x2={xs[i+1]-98} y2={cy}
              fill={animate({ from: 0, to: 1, start: steps[i].at + 0.3, end: steps[i+1].at })(localTime)} op={animate({from:0,to:1,start:steps[i].at,end:steps[i].at+0.3})(localTime)} />
          ))}
          <SceneCaption eyebrow="04 · Authenticate & sign" line={<span>A glance proves you. Your device does the rest.</span>}
            sub="Face ID unlocks the key · the app shows you every field · your device signs locally · the backend broadcasts · it settles." op={fadeInOut(localTime,7.8,0.9)} />
        </div>
      );
    }}</Sprite>
  );
}

// ── Scene 6, Resolution ─────────────────────────────────────────────────────
function S6End() {
  return (
    <Sprite start={30.2} end={34}>{({ localTime }) => {
      const op = fadeInOut(localTime, 3.8, 0.6);
      return (
        <div style={{ position: 'absolute', inset: 0, opacity: op, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 20 }}>
          <div style={{ display: 'flex', gap: 14 }}>
            {['Self-custody', 'On-device', 'Recoverable'].map((c, i) => (
              <span key={c} style={{ fontFamily: EX_MONO, fontSize: 16, letterSpacing: '0.24em', textTransform: 'uppercase', color: EX.white,
                border: `1px solid ${EX.dark}`, borderRadius: 4, padding: '10px 16px',
                opacity: animate({from:0,to:1,start:0.3 + i*0.25, end:0.8 + i*0.25})(localTime) }}>{c} ✓</span>
            ))}
          </div>
          <div style={{ fontFamily: EX_MONO, fontSize: 60, fontWeight: 600, color: EX.white, letterSpacing: '-0.02em', marginTop: 10 }}>Yours. Provably.</div>
          <div style={{ fontFamily: EX_MONO, fontSize: 14, letterSpacing: '0.3em', textTransform: 'uppercase', color: EX.amber, border: `1px solid ${EX.amber}`, padding: '8px 14px', borderRadius: 4, marginTop: 8 }}>Patent Pending · USPTO 63/860,921</div>
        </div>
      );
    }}</Sprite>
  );
}

function ExplainerMovie() {
  return (
    <React.Fragment>
      <Chrome />
      <S1Hook /><S2Secret /><S3Encrypt /><S4Mint /><S5Sign /><S6End />
    </React.Fragment>
  );
}

window.ExplainerMovie = ExplainerMovie;
