// framework.jsx — reusable video-demo framework
// Copilot chat chrome (GitHub Copilot in VS Code), MCP tool-call chips,
// captions, trigger pills, scene markers, record mode, scene primitives.

const T = window.TOKENS;

// ── Record mode: hide playback bar, autoplay from 0 ─────────────
function isRecordMode() {
  try { return new URLSearchParams(location.search).get('record') === '1'; }
  catch { return false; }
}

// ── Typewriter ──────────────────────────────────────────────────
function Typewriter({ text, start = 0, cps = 36, cursor = true, style }) {
  const time = useTime();
  const elapsed = Math.max(0, time - start);
  const n = Math.min(text.length, Math.floor(elapsed * cps));
  const shown = text.slice(0, n);
  const done = n >= text.length;
  const showCursor = cursor && elapsed > 0 && (!done || Math.floor(time * 2) % 2 === 0);
  return (
    <span style={style}>
      {shown}
      {showCursor && <span style={{
        display: 'inline-block', width: '0.55em',
        background: T.cyan, color: T.cyan, marginLeft: 1, opacity: 0.85,
      }}>&nbsp;</span>}
    </span>
  );
}

// ── VS Code window chrome ───────────────────────────────────────
function VSCodeWindow({ filename, path, branch = 'main', sidebar, rightPanel, children }) {
  return (
    <div style={{
      position: 'absolute', inset: 0,
      background: T.ide.bg, color: T.ide.text,
      fontFamily: T.sans,
      display: 'flex', flexDirection: 'column',
      fontSize: T.scale.small,
    }}>
      {/* Title bar */}
      <div style={{
        height: 38, background: T.ide.titlebar,
        display: 'flex', alignItems: 'center', padding: '0 14px', gap: 12,
        flexShrink: 0, borderBottom: `1px solid ${T.ide.border}`,
      }}>
        <div style={{ display: 'flex', gap: 8 }}>
          <div style={{ width: 12, height: 12, borderRadius: 6, background: '#ff5f57' }} />
          <div style={{ width: 12, height: 12, borderRadius: 6, background: '#febc2e' }} />
          <div style={{ width: 12, height: 12, borderRadius: 6, background: '#28c840' }} />
        </div>
        <div style={{ flex: 1, textAlign: 'center', fontSize: 13, color: T.ide.textDim, fontFamily: T.mono }}>
          {path ? `${path}/${filename}` : filename} — agentic-forge
        </div>
        <div style={{ fontSize: 12, color: T.ide.textDim, fontFamily: T.mono, display: 'flex', alignItems: 'center', gap: 6 }}>
          <svg width="12" height="12" viewBox="0 0 16 16" fill="none">
            <circle cx="5" cy="4" r="1.6" stroke="currentColor" strokeWidth="1.2"/>
            <circle cx="5" cy="12" r="1.6" stroke="currentColor" strokeWidth="1.2"/>
            <circle cx="11" cy="8" r="1.6" stroke="currentColor" strokeWidth="1.2"/>
            <path d="M5 5.6v4.8M11 6.4c0 2-2 3-4 3" stroke="currentColor" strokeWidth="1.2"/>
          </svg>
          {branch}
        </div>
      </div>

      {/* Body */}
      <div style={{ flex: 1, display: 'flex', minHeight: 0 }}>
        <ActivityBar />
        {sidebar !== null && (
          <div style={{ width: 260, background: T.ide.panel, borderRight: `1px solid ${T.ide.border}`, display: 'flex', flexDirection: 'column', flexShrink: 0 }}>
            {sidebar || <DefaultFileTree />}
          </div>
        )}
        <div style={{ flex: 1, display: 'flex', flexDirection: 'column', minWidth: 0, minHeight: 0 }}>
          {children}
        </div>
        {rightPanel && (
          <div style={{ width: 560, background: T.ide.chatBg, borderLeft: `1px solid ${T.ide.border}`, display: 'flex', flexDirection: 'column', flexShrink: 0 }}>
            {rightPanel}
          </div>
        )}
      </div>
    </div>
  );
}

function ActivityBar() {
  return (
    <div style={{ width: 48, background: T.ide.panel, display: 'flex', flexDirection: 'column', alignItems: 'center', paddingTop: 10, gap: 14, flexShrink: 0, borderRight: `1px solid ${T.ide.border}` }}>
      {['files','search','git','debug','ext','copilot'].map((k, i) => (
        <div key={k} style={{
          width: 32, height: 32, display: 'flex', alignItems: 'center', justifyContent: 'center',
          borderLeft: i === 0 ? `2px solid ${T.offWhite}` : '2px solid transparent',
          color: i === 5 ? T.cyan : (i === 0 ? T.offWhite : T.ide.textMute),
        }}><ActIcon kind={k}/></div>
      ))}
    </div>
  );
}

function ActIcon({ kind }) {
  const s=18, sw=1.5, c='currentColor';
  switch (kind) {
    case 'files': return <svg width={s} height={s} viewBox="0 0 18 18" fill="none"><path d="M2 3h4l1.5 1.5H16v11H2V3z" stroke={c} strokeWidth={sw} strokeLinejoin="round"/></svg>;
    case 'search': return <svg width={s} height={s} viewBox="0 0 18 18" fill="none"><circle cx="8" cy="8" r="5" stroke={c} strokeWidth={sw}/><path d="M12 12l3 3" stroke={c} strokeWidth={sw} strokeLinecap="round"/></svg>;
    case 'git': return <svg width={s} height={s} viewBox="0 0 18 18" fill="none"><circle cx="5" cy="4" r="2" stroke={c} strokeWidth={sw}/><circle cx="5" cy="14" r="2" stroke={c} strokeWidth={sw}/><circle cx="13" cy="8" r="2" stroke={c} strokeWidth={sw}/><path d="M5 6v6M13 10c0 2-2 3-4 3" stroke={c} strokeWidth={sw}/></svg>;
    case 'debug': return <svg width={s} height={s} viewBox="0 0 18 18" fill="none"><circle cx="9" cy="9" r="4" stroke={c} strokeWidth={sw}/><path d="M9 2v2M9 14v2M2 9h2M14 9h2" stroke={c} strokeWidth={sw} strokeLinecap="round"/></svg>;
    case 'ext': return <svg width={s} height={s} viewBox="0 0 18 18" fill="none"><rect x="3" y="3" width="5" height="5" stroke={c} strokeWidth={sw}/><rect x="10" y="3" width="5" height="5" stroke={c} strokeWidth={sw}/><rect x="3" y="10" width="5" height="5" stroke={c} strokeWidth={sw}/></svg>;
    case 'copilot': return <svg width={s} height={s} viewBox="0 0 18 18" fill="none"><path d="M9 2c-3 0-4.5 1.5-4.5 3.5v2C3 8 2 9 2 11c0 2 1.5 3.5 3.5 3.5h7C14.5 14.5 16 13 16 11c0-2-1-3-2.5-3.5v-2C13.5 3.5 12 2 9 2z" stroke={c} strokeWidth={sw} strokeLinejoin="round"/><circle cx="6.5" cy="10.5" r="1" fill={c}/><circle cx="11.5" cy="10.5" r="1" fill={c}/></svg>;
  }
}

function DefaultFileTree({ items }) {
  const list = items || [
    { d: 0, k: 'folder', n: '.agentic-forge', open: true },
    { d: 1, k: 'folder', n: 'decisions' },
    { d: 1, k: 'folder', n: 'stories' },
    { d: 0, k: 'folder', n: 'src', open: true },
    { d: 1, k: 'folder', n: 'payments', open: true },
    { d: 2, k: 'file', n: 'retry.js', active: true },
    { d: 1, k: 'folder', n: 'config' },
    { d: 0, k: 'file', n: 'package.json' },
  ];
  return (
    <div style={{ padding: '10px 0', fontSize: 13 }}>
      <div style={{ padding: '4px 14px', color: T.ide.textMute, fontSize: 11, fontWeight: 600, letterSpacing: '0.08em' }}>EXPLORER</div>
      {list.map((it, i) => (
        <div key={i} style={{
          display: 'flex', alignItems: 'center', gap: 6,
          padding: '3px 10px', paddingLeft: 10 + it.d * 14,
          background: it.active ? T.ide.lineHl : 'transparent',
          color: it.warn ? T.warn : T.ide.text, fontSize: 13,
        }}>
          {it.k === 'folder' ? <span style={{ color: T.ide.textMute, fontSize: 10, width: 10 }}>{it.open ? '▾' : '▸'}</span> : <span style={{ width: 10 }}/>}
          <span>{it.n}</span>
          {it.warn && <span style={{ color: T.warn, marginLeft: 'auto' }}>!</span>}
        </div>
      ))}
    </div>
  );
}

// ── GitHub Copilot Chat panel (native VS Code look) ─────────────
function CopilotChat({ children, subtitle }) {
  return (
    <div style={{ display: 'flex', flexDirection: 'column', height: '100%', background: T.ide.chatBg }}>
      <div style={{
        padding: '10px 16px', borderBottom: `1px solid ${T.ide.border}`,
        display: 'flex', alignItems: 'center', gap: 10, flexShrink: 0, background: T.ide.panel,
      }}>
        <svg width="18" height="18" viewBox="0 0 18 18" fill="none">
          <path d="M9 2c-3 0-4.5 1.5-4.5 3.5v2C3 8 2 9 2 11c0 2 1.5 3.5 3.5 3.5h7C14.5 14.5 16 13 16 11c0-2-1-3-2.5-3.5v-2C13.5 3.5 12 2 9 2z" stroke={T.ide.text} strokeWidth="1.4"/>
          <circle cx="6.5" cy="10.5" r="1" fill={T.ide.text}/><circle cx="11.5" cy="10.5" r="1" fill={T.ide.text}/>
        </svg>
        <div style={{ fontSize: 13, fontWeight: 600, color: T.ide.text }}>GitHub Copilot</div>
        {subtitle && <div style={{ fontSize: 11, color: T.ide.textMute, fontFamily: T.mono }}>· {subtitle}</div>}
        <div style={{ marginLeft: 'auto', display: 'flex', gap: 6, alignItems: 'center' }}>
          <MCPBadge />
        </div>
      </div>
      <div style={{ flex: 1, overflow: 'hidden', display: 'flex', flexDirection: 'column' }}>
        {children}
      </div>
      <ChatInputBar />
    </div>
  );
}

function MCPBadge() {
  return (
    <div style={{
      display: 'inline-flex', alignItems: 'center', gap: 6,
      padding: '3px 8px', borderRadius: 4,
      background: T.indigoSoft, border: `1px solid ${T.indigo}`,
      fontSize: 10, fontFamily: T.mono, color: T.indigo, letterSpacing: '0.05em', fontWeight: 600,
    }}>
      <span style={{ width: 6, height: 6, borderRadius: 3, background: T.indigo, boxShadow: `0 0 6px ${T.indigo}` }} />
      MCP · agentic-forge
    </div>
  );
}

function ChatInputBar() {
  return (
    <div style={{ padding: 12, borderTop: `1px solid ${T.ide.border}`, flexShrink: 0 }}>
      <div style={{
        background: T.ide.panelAlt, border: `1px solid ${T.ide.border}`, borderRadius: 6,
        padding: '10px 12px', display: 'flex', alignItems: 'center', gap: 10,
        fontSize: 13, color: T.ide.textMute, fontFamily: T.sans,
      }}>
        <span style={{ fontSize: 15 }}>@</span>
        <span>Ask Copilot…</span>
        <span style={{ marginLeft: 'auto', fontFamily: T.mono, fontSize: 10 }}>⌘I</span>
      </div>
    </div>
  );
}

// ── MCP tool-call chip ──────────────────────────────────────────
function MCPToolCall({ name, args, result, start = 0, expandAt = 0.5 }) {
  const time = useTime();
  const elapsed = Math.max(0, time - start);
  const expanded = elapsed > expandAt;
  const running = elapsed > 0 && elapsed < expandAt;

  return (
    <div style={{
      margin: '10px 0',
      border: `1px solid ${T.indigo}`,
      background: 'rgba(124, 58, 237, 0.06)',
      borderRadius: 6, overflow: 'hidden',
    }}>
      <div style={{
        padding: '8px 12px', display: 'flex', alignItems: 'center', gap: 10,
        borderBottom: expanded ? `1px solid ${T.indigo}` : 'none',
        background: 'rgba(124, 58, 237, 0.08)',
      }}>
        <svg width="12" height="12" viewBox="0 0 12 12" fill="none">
          <path d="M6 1l4.5 2.5v5L6 11 1.5 8.5v-5L6 1z" stroke={T.indigo} strokeWidth="1.2"/>
          <circle cx="6" cy="6" r="1.5" fill={T.indigo}/>
        </svg>
        <span style={{ fontFamily: T.mono, fontSize: 11, color: T.indigo, fontWeight: 600 }}>mcp · agentic-forge</span>
        <span style={{ fontFamily: T.mono, fontSize: 11, color: T.ide.text }}>{name}({args && <span style={{ color: T.ide.textDim }}>{args}</span>})</span>
        <div style={{ marginLeft: 'auto', fontSize: 10, fontFamily: T.mono, color: running ? T.warn : T.success }}>
          {running ? '● running' : expanded ? '✓ done' : ''}
        </div>
      </div>
      {expanded && result && (
        <div style={{ padding: '8px 12px', fontSize: 12, color: T.ide.text, lineHeight: 1.5, opacity: Math.min(1, (elapsed - expandAt) / 0.3) }}>
          {result}
        </div>
      )}
    </div>
  );
}

// ── Chat message primitives ─────────────────────────────────────
function UserMsg({ children, avatar = 'E' }) {
  return (
    <div style={{ padding: '14px 16px', borderBottom: `1px solid ${T.ide.border}` }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 6 }}>
        <div style={{ width: 20, height: 20, borderRadius: 10, background: T.obsidianSoft, display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 11, color: T.offWhite, fontWeight: 600 }}>{avatar}</div>
        <div style={{ fontSize: 12, color: T.ide.text, fontWeight: 600 }}>You</div>
      </div>
      <div style={{ fontSize: 14, color: T.ide.text, lineHeight: 1.5, paddingLeft: 28 }}>
        {children}
      </div>
    </div>
  );
}

function CopilotMsg({ children }) {
  return (
    <div style={{ padding: '14px 16px', borderBottom: `1px solid ${T.ide.border}`, background: 'rgba(255,255,255,0.01)' }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 6 }}>
        <svg width="20" height="20" viewBox="0 0 18 18" fill="none">
          <path d="M9 2c-3 0-4.5 1.5-4.5 3.5v2C3 8 2 9 2 11c0 2 1.5 3.5 3.5 3.5h7C14.5 14.5 16 13 16 11c0-2-1-3-2.5-3.5v-2C13.5 3.5 12 2 9 2z" stroke={T.ide.text} strokeWidth="1.4"/>
          <circle cx="6.5" cy="10.5" r="1" fill={T.ide.text}/><circle cx="11.5" cy="10.5" r="1" fill={T.ide.text}/>
        </svg>
        <div style={{ fontSize: 12, color: T.ide.text, fontWeight: 600 }}>GitHub Copilot</div>
      </div>
      <div style={{ fontSize: 14, color: T.ide.text, lineHeight: 1.55, paddingLeft: 28 }}>
        {children}
      </div>
    </div>
  );
}

// ── Trigger pill + scene marker ─────────────────────────────────
function TriggerPill({ kind = 'EVENT-DRIVEN', label }) {
  const color = kind === 'CONVERSATIONAL' ? T.cyan : kind === 'HYBRID' ? T.indigo : T.hyperGreen;
  return (
    <div style={{
      position: 'absolute', top: 20, left: 72, zIndex: 20,
      display: 'inline-flex', alignItems: 'center', gap: 10,
      padding: '8px 14px', background: 'rgba(8,12,20,0.82)', backdropFilter: 'blur(8px)',
      border: `1px solid ${color}`, borderRadius: 999,
      fontFamily: T.mono, fontSize: 12, color: '#fff',
      letterSpacing: '0.04em', whiteSpace: 'nowrap',
    }}>
      <span style={{ width: 8, height: 8, borderRadius: 4, background: color, boxShadow: `0 0 10px ${color}` }} />
      <span style={{ color, fontWeight: 600 }}>{kind}</span>
      <span style={{ opacity: 0.4 }}>|</span>
      <span>{label}</span>
    </div>
  );
}

function SceneMarker({ title }) {
  return (
    <div style={{
      position: 'absolute', top: 20, right: 20, zIndex: 20, whiteSpace: 'nowrap',
      padding: '6px 12px', background: 'rgba(8,12,20,0.75)', backdropFilter: 'blur(8px)',
      borderRadius: 999, fontFamily: T.mono, fontSize: 11, color: T.ide.textDim,
      letterSpacing: '0.06em', border: `1px solid ${T.ide.border}`,
    }}>
      <span style={{ color: T.hyperGreen }}>●</span>
      <span style={{ margin: '0 10px', color: T.offWhite }}>{title}</span>
    </div>
  );
}

// ── Captions bar ────────────────────────────────────────────────
function Captions({ captions }) {
  const time = useTime();
  const cur = captions.find(c => time >= c.t && time < c.t + c.d);
  if (!cur) return null;
  const into = Math.min(1, (time - cur.t) / 0.25);
  const outOf = Math.min(1, (cur.t + cur.d - time) / 0.3);
  return (
    <div style={{
      position: 'absolute', left: '50%', bottom: 56, transform: 'translateX(-50%)',
      maxWidth: '80%', padding: '14px 28px',
      background: 'rgba(8,12,20,0.88)', backdropFilter: 'blur(10px)',
      borderRadius: 10, fontFamily: T.sans, fontSize: 26, fontWeight: 400,
      color: T.offWhite, textAlign: 'center', lineHeight: 1.4,
      opacity: Math.min(into, outOf), boxShadow: '0 10px 40px rgba(0,0,0,0.5)',
      border: '1px solid rgba(255,255,255,0.06)', zIndex: 100,
    }}>{cur.text}</div>
  );
}

// ── Syntax tokenizer + code block ───────────────────────────────
function tokenize(line) {
  const patterns = [
    [/^\/\/[^\n]*/, 'comment'],
    [/^(const|let|var|function|import|from|export|return|if|else|await|async|new|class|try|catch|throw)\b/, 'keyword'],
    [/^'[^']*'/, 'string'], [/^"[^"]*"/, 'string'], [/^`[^`]*`/, 'string'],
    [/^\b\d+(?:\.\d+)?\b/, 'number'],
    [/^\b(true|false|null|undefined)\b/, 'number'],
    [/^\b[A-Z][A-Za-z0-9_]*\b/, 'type'],
    [/^\b[a-z_][A-Za-z0-9_]*(?=\()/, 'fn'],
    [/^\b[a-z_][A-Za-z0-9_]*\b/, 'var'],
    [/^[{}()\[\];,.<>=+\-*/!?:&|]+/, 'punct'],
    [/^\s+/, 'ws'], [/^./, 'punct'],
  ];
  const out = []; let s = line;
  while (s.length) {
    let matched = false;
    for (const [re, k] of patterns) {
      const m = s.match(re);
      if (m) { out.push({ k, t: m[0] }); s = s.slice(m[0].length); matched = true; break; }
    }
    if (!matched) { out.push({ k: 'punct', t: s[0] }); s = s.slice(1); }
  }
  return out;
}

function CodeLine({ text, num, hl, added, removed, warn }) {
  const tokens = tokenize(text);
  return (
    <div style={{
      display: 'flex', background: added ? T.successSoft : removed ? T.dangerSoft : hl ? T.ide.lineHl : 'transparent',
      borderLeft: warn ? `2px solid ${T.warn}` : '2px solid transparent', minHeight: 24,
    }}>
      <div style={{ width: 52, flexShrink: 0, textAlign: 'right', paddingRight: 18,
        color: T.ide.gutter, fontFamily: T.mono, fontSize: 14, lineHeight: '24px', userSelect: 'none' }}>
        {added ? '+' : removed ? '-' : num}
      </div>
      <div style={{ flex: 1, fontFamily: T.mono, fontSize: 14, lineHeight: '24px', color: T.ide.text, whiteSpace: 'pre' }}>
        {tokens.map((tk, i) => <span key={i} style={{ color: tk.k === 'ws' ? 'inherit' : (T.syn[tk.k] || T.ide.text) }}>{tk.t}</span>)}
      </div>
    </div>
  );
}

function CodeBlock({ lines, startLine = 1 }) {
  return (
    <div style={{ background: T.ide.bg, padding: '14px 0', flex: 1, overflow: 'hidden' }}>
      {lines.map((l, i) => {
        const o = typeof l === 'string' ? { text: l } : l;
        return <CodeLine key={i} num={startLine + i} {...o} />;
      })}
    </div>
  );
}

function TabBar({ tabs = [], active = 0 }) {
  return (
    <div style={{ display: 'flex', background: T.ide.panel, borderBottom: `1px solid ${T.ide.border}`, height: 36, flexShrink: 0 }}>
      {tabs.map((t, i) => (
        <div key={i} style={{
          padding: '0 16px', display: 'flex', alignItems: 'center', gap: 8,
          background: i === active ? T.ide.bg : T.ide.panel,
          borderRight: `1px solid ${T.ide.border}`,
          borderTop: i === active ? `2px solid ${T.hyperGreen}` : '2px solid transparent',
          fontFamily: T.mono, fontSize: 12,
          color: i === active ? T.ide.text : T.ide.textMute,
        }}>
          <span style={{ color: t.warn ? T.warn : T.hyperGreen }}>◦</span>
          {t.name}{t.modified && <span style={{ color: T.ide.textMute }}>●</span>}
        </div>
      ))}
    </div>
  );
}

function StatusBar({ items = [] }) {
  return (
    <div style={{ height: 28, background: T.obsidian, display: 'flex', alignItems: 'center', padding: '0 14px', gap: 18, fontFamily: T.mono, fontSize: 11, color: '#fff', flexShrink: 0 }}>
      {items.map((it, i) => <span key={i} style={{ opacity: it.dim ? 0.6 : 1 }}>{it.text}</span>)}
    </div>
  );
}

function Terminal({ lines = [], prompt = '~/projects/agentic-forge' }) {
  return (
    <div style={{ background: '#050608', borderTop: `1px solid ${T.ide.border}`, padding: '14px 18px', flex: 1, fontFamily: T.mono, fontSize: 14, color: T.ide.text, lineHeight: 1.6 }}>
      <div style={{ display: 'flex', gap: 10, fontSize: 11, color: T.ide.textMute, paddingBottom: 10, borderBottom: `1px solid ${T.ide.border}`, marginBottom: 10 }}>
        TERMINAL · bash
      </div>
      {lines.map((l, i) => {
        const o = typeof l === 'string' ? { cmd: true, text: l } : l;
        return (
          <div key={i}>
            {o.cmd && <><span style={{ color: T.hyperGreen }}>➜</span> <span style={{ color: T.cyan }}>{prompt}</span> </>}
            <span style={{ color: o.color || T.ide.text }}>{o.text}</span>
          </div>
        );
      })}
    </div>
  );
}

// ── Citation + check row ────────────────────────────────────────
function Citation({ children }) {
  return <span style={{ fontFamily: T.mono, fontSize: 12, padding: '1px 7px', background: T.ide.bg, border: `1px solid ${T.ide.border}`, borderRadius: 3, color: T.cyan, whiteSpace: 'nowrap' }}>{children}</span>;
}

function CheckRow({ pass, label, detail, cite }) {
  return (
    <div style={{ display: 'flex', gap: 12, padding: '10px 14px', borderBottom: `1px solid ${T.ide.border}`, alignItems: 'flex-start' }}>
      <div style={{ width: 20, height: 20, borderRadius: 10, background: pass ? T.success : T.danger, color: T.carbon, display: 'flex', alignItems: 'center', justifyContent: 'center', fontWeight: 700, fontSize: 12, flexShrink: 0, marginTop: 1 }}>
        {pass ? '✓' : '✕'}
      </div>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ fontSize: 13, color: T.ide.text, marginBottom: detail || cite ? 4 : 0 }}>{label}</div>
        {detail && <div style={{ fontSize: 12, color: T.ide.textDim, marginBottom: cite ? 4 : 0 }}>{detail}</div>}
        {cite && <Citation>{cite}</Citation>}
      </div>
    </div>
  );
}

// ── End-of-demo card ────────────────────────────────────────────
// Fades in over the last `revealDur` seconds. Shows Next (from
// window.__nextDemo injected by the layout) + Replay. Clicking Next
// navigates the parent frame to /demos/<slug>/ so the marketing copy
// updates too; Replay seeks the stage back to 0 and resumes playing.
const END_CARD_REVEAL = 1.5; // seconds before duration where card starts fading in

function EndCard() {
  const { time, duration, setTime, setPlaying } = useTimeline();
  const next = (typeof window !== 'undefined' && window.__nextDemo) || null;

  const triggerAt = Math.max(0, duration - END_CARD_REVEAL);
  if (time < triggerAt) return null;

  const o = Math.min(1, (time - triggerAt) / END_CARD_REVEAL);

  const onNext = () => {
    if (!next) return;
    try {
      const target = `/demos/${next.slug}/`;
      // If embedded in the marketing iframe (same-origin), navigate the
      // parent; otherwise navigate self.
      if (window.parent && window.parent !== window) window.parent.location.href = target;
      else window.location.href = target;
    } catch (_) {
      window.location.href = `/demos/${next.slug}/`;
    }
  };
  const onReplay = () => {
    if (setTime) setTime(0);
    if (setPlaying) setPlaying(true);
  };

  return (
    <div style={{
      position: 'absolute', inset: 0, zIndex: 300,
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      background: 'rgba(8,12,20,0.78)', backdropFilter: 'blur(6px)',
      opacity: o, transition: 'none',
      fontFamily: T.sans,
    }}>
      <div style={{
        maxWidth: 720, padding: '56px 40px 64px', textAlign: 'center',
        background: 'url(/assets/images/bg_arcs.jpg) center/cover no-repeat',
        border: '1px solid rgba(250, 250, 250, 0.1)',
        borderRadius: 6, overflow: 'hidden',
        color: T.offWhite,
        boxShadow: '0 8px 32px rgba(0,0,0,0.3)',
        textShadow: '0 2px 12px rgba(0,0,0,0.7)',
      }}>
        <div style={{
          fontSize: 16, fontWeight: 500, color: '#00da41',
          textTransform: 'uppercase', letterSpacing: '0.1em',
          marginBottom: 4, minHeight: 56,
          display: 'flex', alignItems: 'center', justifyContent: 'center',
        }}>
          {next ? 'UP NEXT' : 'END OF DEMO'}
        </div>
        {next && (
          <>
            <div style={{ fontSize: 34, fontWeight: 500, lineHeight: 1.25, marginBottom: 10 }}>{next.title}</div>
            {next.subtitle && (
              <div style={{ fontSize: 18, color: T.offWhite, lineHeight: 1.5, marginBottom: 56, fontWeight: 200 }}>
                {next.subtitle}
              </div>
            )}
          </>
        )}
        <div style={{ display: 'flex', gap: 14, justifyContent: 'center', marginTop: next ? 0 : 28 }}>
          <button
            onClick={onReplay}
            style={{
              background: 'transparent', color: T.offWhite,
              border: '1px solid rgba(250, 250, 250, 0.2)', borderRadius: 6,
              padding: '8px 20px', fontSize: 16, fontWeight: 500,
              fontFamily: T.sans, cursor: 'pointer', textShadow: 'none',
            }}
          >
            Replay
          </button>
          {next && (
            <button
              onClick={onNext}
              style={{
                background: '#00E87B', color: '#080C14', border: 'none',
                borderRadius: 6, padding: '8px 20px', fontSize: 16, fontWeight: 500,
                fontFamily: T.sans, cursor: 'pointer', textShadow: 'none',
                display: 'inline-flex', alignItems: 'center', gap: 8,
              }}
            >
              <span>Watch next</span>
              <svg width="14" height="14" viewBox="0 0 16 16" fill="none" aria-hidden="true" style={{ transform: 'translateY(1px)' }}><path d="M3 8h10M9 4l4 4-4 4" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/></svg>
            </button>
          )}
        </div>
      </div>
    </div>
  );
}

// ── Framework Stage wrapper with record mode ────────────────────
// `showCaptions` defaults to false — these demos autoplay without
// voiceover, so burned-in captions fight the on-canvas text. The
// SUBS arrays are kept in the scene files for when voiceover lands.
// Flip to true (here, or per scene via prop) to re-enable.
//
// `loop` defaults to false — the demo ends with an EndCard overlay
// pointing at the next demo in demos.yaml. Pass loop={true} to
// re-enable the old behavior (and the EndCard never gets a chance
// to mount because the stage rewinds before time === duration).
function DemoStage({ duration = 180, children, captions = [], showCaptions = false, loop = false }) {
  const record = isRecordMode();

  // In record mode: render raw 1920x1080 with no scaler, no playback bar
  if (record) {
    return <RawStage duration={duration} captions={captions} showCaptions={showCaptions}>{children}</RawStage>;
  }
  return (
    <Stage width={1920} height={1080} duration={duration} background={T.carbon} loop={loop}>
      {children}
      {showCaptions && <Captions captions={captions} />}
      <EndCard />
    </Stage>
  );
}

// Record stage: auto-plays from 0, fills viewport exactly 1920x1080 (set browser to that)
function RawStage({ duration, captions, children, showCaptions = false }) {
  const [time, setTime] = React.useState(0);
  React.useEffect(() => {
    let start = null, raf;
    const step = (ts) => {
      if (start == null) start = ts;
      const t = (ts - start) / 1000;
      if (t >= duration) { setTime(duration); return; }
      setTime(t);
      raf = requestAnimationFrame(step);
    };
    raf = requestAnimationFrame(step);
    return () => cancelAnimationFrame(raf);
  }, [duration]);
  const ctx = React.useMemo(() => ({ time, duration, playing: true }), [time, duration]);
  return (
    <div style={{ width: 1920, height: 1080, position: 'relative', background: T.carbon, overflow: 'hidden' }}>
      <TimelineContext.Provider value={ctx}>
        {children}
        {showCaptions && <Captions captions={captions} />}
      </TimelineContext.Provider>
    </div>
  );
}

Object.assign(window, {
  Typewriter, VSCodeWindow, DefaultFileTree, ActivityBar,
  CopilotChat, MCPBadge, MCPToolCall, UserMsg, CopilotMsg,
  TriggerPill, SceneMarker, Captions, EndCard,
  CodeBlock, CodeLine, TabBar, StatusBar, Terminal,
  Citation, CheckRow,
  DemoStage, isRecordMode,
});
