// tech-scenes.jsx — EpochCore technical demo (~120s).
// Animated stack diagram + simulated cursor that zooms/pinpoints each stage
// as the caption (VO-ready) describes it. Loaded after animations.jsx.

const T_BG = '#0c0a13';
const T_INK = '#f3f0fa';
const T_DIM = 'rgba(243,240,250,0.6)';
const T_VIOLET = '#7d5bf4';
const T_VIOLET2 = '#a896f7';
const T_GREEN = '#2dd881';
const T_AMBER = '#f5a623';
const T_IBM = '#78a9ff';
const T_SERIF = 'Newsreader, Georgia, serif';
const T_MONO = 'JetBrains Mono, ui-monospace, monospace';

// ── world node positions (1920×1080) ───────────────────────────────────────
const NODES = {
  file:   { x: 250,  y: 430, w: 220, h: 150, label: 'Your file', sub: 'video · doc · audio', icon: 'file', color: T_INK },
  mark:   { x: 620,  y: 430, w: 220, h: 150, label: 'Mark',   sub: 'invisible watermark', icon: 'mark', color: T_VIOLET2 },
  seal:   { x: 990,  y: 430, w: 220, h: 150, label: 'Seal',   sub: 'hash + signature', icon: 'seal', color: T_VIOLET2 },
  anchor: { x: 1360, y: 430, w: 220, h: 150, label: 'Anchor', sub: 'tamper-proof ledger', icon: 'anchor', color: T_VIOLET2 },
  verify: { x: 1660, y: 430, w: 220, h: 150, label: 'Verify', sub: 'offline check', icon: 'verify', color: T_GREEN },
  cell:   { x: 990,  y: 760, w: 300, h: 150, label: 'SignCellTech', sub: 'prove a URL or screen', icon: 'cell', color: T_AMBER },
};
const ORDER = ['file', 'mark', 'seal', 'anchor', 'verify'];

function center(n) { return [n.x + n.w / 2, n.y + n.h / 2]; }

const ICONS = {
  file: 'M14 3H7a2 2 0 00-2 2v14a2 2 0 002 2h10a2 2 0 002-2V8z M14 3v5h5',
  mark: 'M3 5h18v12H3z M15 12l3 3 M13 10l-1.5 1.5',
  seal: 'M12 2l8 4v6c0 5-3.5 8-8 10-4.5-2-8-5-8-10V6z M9 12l2 2 4-4',
  anchor: 'M5 6h14v12H5z M5 10h14 M9 6v12',
  verify: 'M5 12l4 4 10-10',
  cell: 'M12 3a9 9 0 100 18 9 9 0 000-18 M3 12h18',
};
function NodeIcon({ d, color }) {
  return <svg width="34" height="34" viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><path d={d}/></svg>;
}

// ── a diagram node, with highlight pulse when focused ───────────────────────
function Node({ id, focusId, t }) {
  const n = NODES[id];
  const focused = focusId === id;
  const pulse = focused ? 0.5 + 0.5 * Math.sin(t * 4) : 0;
  return (
    <div style={{ position: 'absolute', left: n.x, top: n.y, width: n.w, height: n.h,
      borderRadius: 18, background: focused ? 'rgba(125,91,244,0.12)' : 'rgba(255,255,255,0.03)',
      border: `2px solid ${focused ? n.color : 'rgba(255,255,255,0.12)'}`,
      boxShadow: focused ? `0 0 ${30 + pulse * 30}px ${n.color}66` : 'none',
      transition: 'background 0.3s', display: 'flex', flexDirection: 'column',
      padding: '20px 22px', justifyContent: 'space-between' }}>
      <div style={{ width: 56, height: 56, borderRadius: 13, background: `${n.color}1e`,
        border: `1px solid ${n.color}55`, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
        <NodeIcon d={ICONS[n.icon]} color={n.color} />
      </div>
      <div>
        <div style={{ fontFamily: T_SERIF, fontWeight: 700, fontSize: 30, color: T_INK, letterSpacing: '-0.02em' }}>{n.label}</div>
        <div style={{ fontFamily: T_MONO, fontSize: 13, color: T_DIM, marginTop: 4, letterSpacing: '0.02em' }}>{n.sub}</div>
      </div>
    </div>
  );
}

// ── connector arrow between two nodes (animated draw) ───────────────────────
function Arrow({ from, to, t, lit }) {
  const a = NODES[from], b = NODES[to];
  const x1 = a.x + a.w, y1 = a.y + a.h / 2;
  const x2 = b.x, y2 = b.y + b.h / 2;
  const mid = (x1 + x2) / 2;
  return (
    <svg style={{ position: 'absolute', left: 0, top: 0, width: 1920, height: 1080, overflow: 'visible', pointerEvents: 'none' }}>
      <defs><marker id={'ah' + from} markerWidth="10" markerHeight="10" refX="7" refY="3" orient="auto">
        <path d="M0 0l6 3-6 3z" fill={lit ? T_VIOLET2 : 'rgba(255,255,255,0.25)'} /></marker></defs>
      <path d={`M${x1} ${y1} C${mid} ${y1} ${mid} ${y2} ${x2} ${y2}`} fill="none"
        stroke={lit ? T_VIOLET2 : 'rgba(255,255,255,0.18)'} strokeWidth={lit ? 3 : 2}
        markerEnd={`url(#ah${from})`} strokeDasharray={lit ? '0' : '6 6'} />
      {lit && (() => { // moving packet
        const p = (t % 1.2) / 1.2;
        const px = x1 + (x2 - x1) * p, py = y1 + (y2 - y1) * p;
        return <circle cx={px} cy={py} r="6" fill={T_GREEN} />;
      })()}
    </svg>
  );
}

// ── simulated cursor ────────────────────────────────────────────────────────
function Cursor({ x, y, click }) {
  return (
    <div style={{ position: 'absolute', left: x, top: y, transform: 'translate(-3px,-2px)', zIndex: 50,
      filter: 'drop-shadow(0 3px 6px rgba(0,0,0,0.6))', transition: 'none' }}>
      {click > 0 && <div style={{ position: 'absolute', left: -8, top: -8, width: 36, height: 36,
        marginLeft: -10, marginTop: -10, borderRadius: '50%', border: `3px solid ${T_VIOLET2}`,
        opacity: 1 - click, transform: `scale(${0.4 + click * 1.4})` }} />}
      <svg width="34" height="34" viewBox="0 0 24 24" fill="#fff" stroke="#0c0a13" strokeWidth="1.2">
        <path d="M5 3l14 7-6 1.5L10 18z"/></svg>
    </div>
  );
}

// ── callout card (screen-space, describes the focused stage) ────────────────
function Callout({ title, lines, color = T_VIOLET2 }) {
  const { localTime, progress } = useSprite();
  const inT = Easing.easeOutCubic(clamp(localTime / 0.5, 0, 1));
  const outT = progress > 0.88 ? (progress - 0.88) / 0.12 : 0;
  const op = Math.min(inT, 1 - outT);
  return (
    <div style={{ position: 'absolute', left: 120, top: 760, width: 720, opacity: op,
      transform: `translateY(${(1 - inT) * 18}px)` }}>
      <div style={{ fontFamily: T_MONO, fontSize: 15, letterSpacing: '0.16em', textTransform: 'uppercase',
        color, marginBottom: 14 }}>{title}</div>
      {lines.map((l, i) => (
        <div key={i} style={{ fontFamily: T_SERIF, fontSize: 31, color: T_INK, lineHeight: 1.4,
          opacity: clamp((localTime - 0.3 - i * 0.25) / 0.4, 0, 1) }}>{l}</div>
      ))}
    </div>
  );
}

// ── caption (VO-ready) ──────────────────────────────────────────────────────
function TCaption({ children }) {
  const { progress, duration } = useSprite();
  const inT = Math.min(1, (progress * duration) / 0.4);
  const outT = progress > 0.9 ? (progress - 0.9) / 0.1 : 0;
  const op = Math.min(inT, 1 - outT);
  return (
    <div style={{ position: 'absolute', left: 0, right: 0, bottom: 40, textAlign: 'center', opacity: op }}>
      <span style={{ fontFamily: T_SERIF, fontSize: 28, color: T_INK, background: 'rgba(8,6,15,0.6)',
        padding: '9px 22px', borderRadius: 9, letterSpacing: '-0.01em' }}>{children}</span>
    </div>
  );
}

// ── camera helpers: keyframed focus ─────────────────────────────────────────
function cam(t) {
  // [time, focusId, scale]
  const KF = [
    [0, null, 1.0], [7, null, 1.0],
    [14, 'mark', 1.0], [20, 'mark', 1.62], [36, 'mark', 1.62],
    [40, 'seal', 1.62], [56, 'seal', 1.62],
    [60, 'anchor', 1.62], [74, 'anchor', 1.62],
    [78, 'verify', 1.62], [92, 'verify', 1.62],
    [96, 'cell', 1.42], [110, 'cell', 1.42],
    [113, null, 1.0], [120, null, 1.0],
  ];
  let i = 0; while (i < KF.length - 1 && t > KF[i + 1][0]) i++;
  const A = KF[i], B = KF[Math.min(i + 1, KF.length - 1)];
  const span = B[0] - A[0] || 1;
  const lt = Easing.easeInOutCubic(clamp((t - A[0]) / span, 0, 1));
  const sc = A[2] + (B[2] - A[2]) * lt;
  const ca = A[1] ? center(NODES[A[1]]) : [960, 480];
  const cb = B[1] ? center(NODES[B[1]]) : [960, 480];
  const cx = ca[0] + (cb[0] - ca[0]) * lt;
  const cy = ca[1] + (cb[1] - ca[1]) * lt;
  const focusId = lt > 0.5 ? B[1] : A[1];
  return { sc, cx, cy, focusId };
}

// cursor world target per time (slight ease/lag, points to focused node)
function cursorTarget(t) {
  const c = cam(t);
  if (c.focusId) { const n = NODES[c.focusId]; return [n.x + n.w - 40, n.y + n.h - 36]; }
  // overview: glide across the pipeline
  const p = clamp((t - 7) / 7, 0, 1);
  return [400 + p * 1200, 360];
}

function TechFilm() {
  const t = useTime();
  const C = cam(t);
  const camTx = 960 - C.cx * C.sc;
  const camTy = 540 - C.cy * C.sc;
  const [curX, curY] = cursorTarget(t);

  // click pulse when a focus settles (every ~zoom arrival)
  const clickAt = [22, 42, 62, 80, 98];
  let click = 0;
  for (const ca of clickAt) { if (t >= ca && t < ca + 0.6) click = (t - ca) / 0.6; }

  return (
    <div style={{ position: 'absolute', inset: 0, background: T_BG, overflow: 'hidden' }}>
      <div style={{ position: 'absolute', inset: 0,
        background: 'radial-gradient(110% 80% at 50% 30%, rgba(125,91,244,0.12), transparent 60%)' }} />

      {/* title 0–7 */}
      <Sprite start={0.3} end={7.5}>{() => {
        const lt = useSprite().localTime;
        const a = Easing.easeOutBack(clamp(lt / 0.6, 0, 1));
        return <div style={{ position: 'absolute', left: 0, right: 0, top: 420, textAlign: 'center',
          opacity: clamp(lt / 0.5, 0, 1), transform: `translateY(${(1 - a) * 20}px)` }}>
          <div style={{ fontFamily: T_MONO, fontSize: 18, letterSpacing: '0.22em', textTransform: 'uppercase',
            color: T_VIOLET2, marginBottom: 18 }}>Technical Overview</div>
          <div style={{ fontFamily: T_SERIF, fontWeight: 800, fontSize: 92, color: T_INK, letterSpacing: '-0.03em' }}>
            How EpochCore proves a file</div>
        </div>;
      }}</Sprite>

      {/* the world (camera-transformed) 7–113 */}
      <Sprite start={7} end={120} keepMounted>
        <div style={{ position: 'absolute', inset: 0, transformOrigin: '0 0',
          transform: `translate(${camTx}px, ${camTy}px) scale(${C.sc})`,
          opacity: clamp((t - 7) / 0.8, 0, 1) }}>
          {/* arrows under nodes */}
          {ORDER.slice(0, -1).map((id, i) => {
            const next = ORDER[i + 1];
            const lit = C.focusId === id || C.focusId === next || (!C.focusId && t > 8);
            return <Arrow key={id} from={id} to={next} t={t} lit={lit} />;
          })}
          {/* cellsign branch arrow from seal down */}
          <Arrow from="seal" to="cell" t={t} lit={C.focusId === 'cell'} />
          {ORDER.map(id => <Node key={id} id={id} focusId={C.focusId} t={t} />)}
          <Node id="cell" focusId={C.focusId} t={t} />
          {/* cursor lives in-world so it zooms with the camera */}
          <Cursor x={curX} y={curY} click={click} />
        </div>
      </Sprite>

      {/* callouts (screen space) */}
      <Sprite start={22} end={36}><Callout title="01 · Mark" color={T_VIOLET2}
        lines={['An invisible pattern is woven into', 'the pixels or audio itself —', 'it survives re-encoding and cropping.']} /></Sprite>
      <Sprite start={42} end={56}><Callout title="02 · Seal" color={T_VIOLET2}
        lines={['Three independent fingerprints +', 'a digital signature lock the file', 'to this exact moment.']} /></Sprite>
      <Sprite start={62} end={74}><Callout title="03 · Anchor" color={T_VIOLET2}
        lines={['The seal is written to a ledger', 'that can only be added to —', 'never edited or erased.']} /></Sprite>
      <Sprite start={80} end={92}><Callout title="04 · Verify" color={T_GREEN}
        lines={['Anyone re-checks the fingerprints', 'and signature locally — pass or fail,', 'with no internet required.']} /></Sprite>
      <Sprite start={98} end={110}><Callout title="＋ SignCellTech" color={T_AMBER}
        lines={['The same engine proves a live', 'web page or screen looked exactly', 'this way, at this time.']} /></Sprite>

      {/* captions */}
      <Sprite start={0.6} end={7.5}><TCaption>Here's how EpochCore turns any file into proof.</TCaption></Sprite>
      <Sprite start={8} end={14}><TCaption>It moves through four stages — mark, seal, anchor, verify.</TCaption></Sprite>
      <Sprite start={20} end={36}><TCaption>First, an invisible mark is woven into the file itself.</TCaption></Sprite>
      <Sprite start={40} end={56}><TCaption>Then three fingerprints and a signature seal it to this moment.</TCaption></Sprite>
      <Sprite start={60} end={74}><TCaption>The seal is anchored to an append-only ledger — it can never be altered.</TCaption></Sprite>
      <Sprite start={78} end={92}><TCaption>Anyone can verify it locally — pass or fail — even fully offline.</TCaption></Sprite>
      <Sprite start={96} end={110}><TCaption>SignCellTech extends the same proof to any live web page or screen.</TCaption></Sprite>

      {/* close 113–120 */}
      <Sprite start={113} end={120}>{() => {
        const lt = useSprite().localTime;
        const a = Easing.easeOutBack(clamp(lt / 0.6, 0, 1));
        return <div style={{ position: 'absolute', inset: 0, display: 'flex', flexDirection: 'column',
          alignItems: 'center', justifyContent: 'center', opacity: clamp(lt / 0.5, 0, 1) }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 22, transform: `scale(${0.9 + 0.1 * a})` }}>
            <div style={{ width: 56, height: 56, background: `linear-gradient(135deg, ${T_VIOLET}, ${T_VIOLET2})`,
              transform: 'rotate(45deg)', borderRadius: 10, boxShadow: `0 0 32px ${T_VIOLET}` }} />
            <span style={{ fontFamily: T_MONO, fontWeight: 700, fontSize: 56, color: T_INK }}>
              Epoch<span style={{ color: T_VIOLET2 }}>Core</span></span>
            <div style={{ width: 1, height: 44, background: 'rgba(243,240,250,0.25)' }} />
            <span style={{ fontFamily: T_MONO, fontWeight: 700, fontSize: 40, letterSpacing: '2px', color: T_IBM }}>IBM watsonx</span>
          </div>
          <div style={{ fontFamily: T_SERIF, fontSize: 34, color: T_DIM, marginTop: 30 }}>Mark. Seal. Verify. Proven.</div>
        </div>;
      }}</Sprite>
    </div>
  );
}

window.TechFilm = TechFilm;
