// AP2 Fraction Opening Movie — clean center-only
// Geometric motion leading to the AP2 FRACTION logo. 8-second loop.
// No kicker, no HUD, no subhead, no index — just the reveal.

const CC = {
  base:   '#F4F1EA',
  baseDim:'rgba(244,241,234,0.55)',
  baseFaint:'rgba(244,241,234,0.12)',
  ink:    '#0A0A09',
  ink2:   '#141311',
  green:  '#1F3A2E',
  greenL: '#2E5142',
  brass:  '#A08256',
  brassL: '#C4A172',
};

const TAU = Math.PI * 2;
const lerp = (a, b, t) => a + (b - a) * t;

// ───────────────────────────────────────────────
// Scene (8s loop):
//  0.0 – 1.2  grid fades in; scan line sweeps; central axis draws
//  1.2 – 3.0  particles rise from horizon, align to a ring
//  3.0 – 4.8  ring forms; brass orbit hairline rotates; ticks pulse
//  4.8 – 6.0  ring splits vertically, halves slide apart
//  5.2 – 6.8  logo emerges between the halves; green rule draws
//  6.8 – 7.1  logo flash / punch
//  7.1 – 7.9  BURST — ring & logo shatter into particles flying outward
//  7.9 – 8.0  black, ready to loop
// ───────────────────────────────────────────────
function Scene({ isPortrait = false }) {
  const t = useTime();
  const { duration } = useTimeline();
  const W = 1920, H = 1080;
  const cx = W / 2, cy = H / 2;

  // Portrait-mode sizing overrides — stage is still 1920×1080 but the host
  // scales & crops sides, so we shrink the circle & enlarge the text in
  // stage-space so content reads correctly on phones.
  const R = isPortrait ? 130 : 280;
  const splitMaxX = isPortrait ? 130 : 280;
  const logoWidthPct = isPortrait ? '14%' : '22%';
  const subFontSize = isPortrait ? 16 : 24;
  const subLetterSpacing = isPortrait ? 4 : 10;
  const subMarginTop = isPortrait ? 36 : 56;

  // global fade: very gradual outro so ending never feels abrupt
  const inFade  = clamp(t / 0.6, 0, 1);
  const outFade = 1 - Easing.easeInOutCubic(clamp((t - 7.8) / 2.0, 0, 1));
  const globalA = Math.min(inFade, outFade);

  const gridA = interpolate([0.0, 1.2, 6.2, 7.0], [0, 0.08, 0.08, 0], Easing.easeOutCubic)(t);
  const scanY = interpolate([0.2, 1.2], [-40, H + 40], Easing.easeInOutCubic)(t);
  const scanA = interpolate([0.2, 0.6, 1.2], [0, 0.7, 0], Easing.linear)(t);

  const partIn = clamp((t - 0.6) / 1.4, 0, 1);
  const partSettle = clamp((t - 1.6) / 1.4, 0, 1);
  const partOut = 1 - clamp((t - 4.6) / 0.4, 0, 1);

  // Ambient stars (static) — breathing in with soft delay
  const starsA = interpolate([0.0, 1.6, 5.5, 7.0], [0, 0.9, 0.9, 0], Easing.easeInOutCubic)(t);
  const breathe = 0.85 + 0.15 * Math.sin(t * TAU * 0.25);

  const N = 72;

  // Ring draws slowly from the start — no particles, just pure circle drawing
  const ringDraw = Easing.easeInOutCubic(clamp(t / 3.2, 0, 1));
  const ringA = Easing.easeOutCubic(clamp(t / 0.4, 0, 1));

  const splitP = Easing.easeInOutCubic(clamp((t - 3.2) / 1.0, 0, 1));
  const splitX = splitP * splitMaxX;
  // ring + split halves vanish at burst moment
  const splitA = 1 - clamp((t - 6.9) / 0.08, 0, 1);

  // Both monogram (A/P) and wordmark (AP2 | FRACTION) use the same smooth left-to-right sweep
  // Slower than before for a more elegant pen-trace feel
  const monoA = Easing.easeInOutCubic(clamp((t - 3.6) / 1.4, 0, 1));
  const wordA = Easing.easeInOutCubic(clamp((t - 5.0) / 1.8, 0, 1));
  const h1A = Math.max(monoA, wordA); // used elsewhere for fade gating
  const h1Y = 0; // logo doesn't move — stays still until burst

  // ─── Burst phase ───
  // 6.85–7.05: anticipation punch-up
  // 7.05:       flash
  // 7.05–9.55: SLOW shatter — 2.5s so pieces are clearly visible
  const BURST_START = 6.9;
  const BURST_DUR = 2.5;
  const burstT = clamp((t - BURST_START) / BURST_DUR, 0, 1);
  const burstE = Easing.easeOutCubic(burstT);
  // Logo stays at scale 1 until burst moment, then snaps to 0 (it has already shattered into pieces)
  const logoScale = 1;
  const h1Out = 1 - clamp((t - BURST_START) / 0.05, 0, 1);

  const ruleW = Easing.easeInOutCubic(clamp((t - 5.9) / 0.8, 0, 1));
  const ruleOut = 1 - clamp((t - 6.85) / 0.1, 0, 1);

  const axisW = Easing.easeOutCubic(clamp((t - 0.1) / 0.8, 0, 1));

  return (
    <div style={{ position: 'absolute', inset: 0, background: CC.ink, opacity: globalA }}>
      <div style={{ position: 'absolute', inset: 0, background: CC.ink }} />
      {!isPortrait && (
        <div style={{ position: 'absolute', inset: '10% 15%', background: CC.ink2, opacity: 0.5 }} />
      )}

      <svg viewBox={`0 0 ${W} ${H}`} xmlns="http://www.w3.org/2000/svg"
        preserveAspectRatio="xMidYMid slice"
        style={{ position: 'absolute', inset: 0, width: '100%', height: '100%' }}>

        <defs>
          <filter id="softglow" x="-50%" y="-50%" width="200%" height="200%">
            <feGaussianBlur stdDeviation="2.2" />
          </filter>
          <radialGradient id="vignette" cx="50%" cy="50%" r="70%">
            <stop offset="55%" stopColor={CC.ink} stopOpacity="0" />
            <stop offset="100%" stopColor={CC.ink} stopOpacity="0.75" />
          </radialGradient>
        </defs>

        {/* Ambient stars — soft romantic backdrop */}
        <g opacity={starsA}>
          {Array.from({ length: 70 }, (_, i) => {
            const sx = ((i * 2654435761) >>> 0) / 4294967296;
            const sy = ((i * 1597334677) >>> 0) / 4294967296;
            const sr = ((i * 3266489917) >>> 0) / 4294967296;
            const x = sx * W;
            const y = sy * H;
            // per-star slow twinkle
            const tw = 0.6 + 0.4 * Math.sin(t * 1.4 + i * 0.7);
            const isBrass = i % 11 === 0;
            const r = 0.4 + sr * 1.2;
            return (
              <circle key={`st${i}`} cx={x} cy={y} r={r}
                fill={isBrass ? CC.brassL : CC.base}
                opacity={(isBrass ? 0.7 : 0.45) * tw * breathe} />
            );
          })}
        </g>

        {/* particles removed — ring draws on its own */}

        <g opacity={ringA * splitA}>
          <circle cx={cx} cy={cy} r={R}
            fill="none" stroke={CC.base} strokeWidth="1"
            strokeDasharray={`${TAU * R * ringDraw} ${TAU * R}`}
            transform={`rotate(-90 ${cx} ${cy})`} />
          <circle cx={cx} cy={cy} r={R - 24}
            fill="none" stroke={CC.base} strokeWidth="0.5" opacity={0.3 * ringDraw} />
        </g>

        <g opacity={splitA * (splitP > 0.02 ? 1 : 0)}>
          <g transform={`translate(${-splitX} 0)`}>
            <path
              d={`M ${cx} ${cy - R} A ${R} ${R} 0 0 0 ${cx} ${cy + R}`}
              fill="none" stroke={CC.base} strokeWidth="1" />
          </g>
          <g transform={`translate(${splitX} 0)`}>
            <path
              d={`M ${cx} ${cy - R} A ${R} ${R} 0 0 1 ${cx} ${cy + R}`}
              fill="none" stroke={CC.base} strokeWidth="1" />
          </g>
        </g>

        <line
          x1={cx - 140 * ruleW} y1={cy + 200}
          x2={cx + 140 * ruleW} y2={cy + 200}
          stroke={CC.green} strokeWidth="2" opacity={ruleW * ruleOut} />

        {/* ─── BURST — only the things that existed actually shatter ─── */}
        {burstT > 0 && burstT < 1 && (() => {
          const GRAVITY = 380;
          const time = burstT * BURST_DUR;
          const fadeT = clamp((burstT - 0.6) / 0.4, 0, 1);
          const pieceA = 1 - fadeT;

          // Helper: deterministic pseudo-random
          const rand = (n) => ((n * 2654435761) >>> 0) / 4294967296;

          // ── WIND: lateral gust that ramps in, with gentle oscillation
          // Accelerates pieces sideways over time → "blown away" feel
          const WIND_X = 520;   // rightward push strength (px/s²-ish)
          const WIND_Y = -180;  // slight upward lift from wind
          const windRamp = Easing.easeOutCubic(clamp(time / 0.6, 0, 1));
          // Per-piece wind multiplier (some pieces catch more wind than others)
          const windMul = (seed) => 0.55 + seed * 0.9 + Math.sin(time * 3 + seed * 10) * 0.15;

          // ── Ring shatters into many small arc fragments
          const ringChunks = [];
          {
            let a = 0;
            let idx = 0;
            while (a < TAU - 0.005) {
              const span = 0.06 + rand(idx * 7 + 3) * 0.09; // small: ~3–9° per chunk, ~40–60 chunks
              const aEnd = Math.min(a + span, TAU);
              const midA = (a + aEnd) / 2;
              const seed = rand(idx * 13 + 5);
              const seed2 = rand(idx * 31 + 17);
              const speed = 160 + seed * 260;
              const vx = Math.cos(midA) * speed;
              const vy = Math.sin(midA) * speed - 40;
              const wm = windMul(seed);
              const x = cx + vx * time + 0.5 * WIND_X * wm * time * time * windRamp;
              const y = cy + vy * time + 0.5 * GRAVITY * time * time + 0.5 * WIND_Y * wm * time * time * windRamp;
              const spin = (seed2 * 360 + (320 + seed * 480) * time * (seed < 0.5 ? 1 : -1));
              const x1 = Math.cos(a) * R;
              const y1 = Math.sin(a) * R;
              const x2 = Math.cos(aEnd) * R;
              const y2 = Math.sin(aEnd) * R;
              ringChunks.push(
                <g key={`rc${idx}`} transform={`translate(${x} ${y}) rotate(${spin})`} opacity={pieceA}>
                  <path d={`M ${x1} ${y1} A ${R} ${R} 0 0 1 ${x2} ${y2}`}
                    fill="none" stroke={CC.base} strokeWidth="1" strokeLinecap="round" />
                </g>
              );
              a = aEnd;
              idx++;
            }
          }

          // ── Inner ring (r-24) also shatters into small pieces
          const innerChunks = [];
          {
            const Ri = R - 24;
            let a = 0.2;
            let idx = 0;
            while (a < TAU + 0.2 - 0.005) {
              const span = 0.07 + rand(idx * 11 + 9) * 0.11;
              const aEnd = Math.min(a + span, TAU + 0.2);
              const midA = (a + aEnd) / 2;
              const seed = rand(idx * 19 + 23);
              const seed2 = rand(idx * 41 + 37);
              const speed = 130 + seed * 230;
              const vx = Math.cos(midA) * speed;
              const vy = Math.sin(midA) * speed - 30;
              const wm = windMul(seed2);
              const x = cx + vx * time + 0.5 * WIND_X * wm * time * time * windRamp;
              const y = cy + vy * time + 0.5 * GRAVITY * time * time + 0.5 * WIND_Y * wm * time * time * windRamp;
              const spin = (seed2 * 360 + (280 + seed * 440) * time * (seed < 0.5 ? 1 : -1));
              const x1 = Math.cos(a) * Ri;
              const y1 = Math.sin(a) * Ri;
              const x2 = Math.cos(aEnd) * Ri;
              const y2 = Math.sin(aEnd) * Ri;
              innerChunks.push(
                <g key={`ic${idx}`} transform={`translate(${x} ${y}) rotate(${spin})`} opacity={pieceA * 0.5}>
                  <path d={`M ${x1} ${y1} A ${Ri} ${Ri} 0 0 1 ${x2} ${y2}`}
                    fill="none" stroke={CC.base} strokeWidth="0.5" strokeLinecap="round" />
                </g>
              );
              a = aEnd;
              idx++;
            }
          }

          // ── Green rule — breaks into many small pieces
          const greenPieces = [];
          {
            const totalW = 280;
            const startX = cx - 140;
            const startY = cy + 200;
            let x0 = 0;
            let idx = 0;
            while (x0 < totalW - 1) {
              const segLen = 8 + rand(idx * 73 + 11) * 14; // small: 8–22px each
              const segEnd = Math.min(x0 + segLen, totalW);
              const midX = (x0 + segEnd) / 2;
              const seed = rand(idx * 53 + 7);
              const seed2 = rand(idx * 89 + 41);
              const ang = ((midX / totalW) - 0.5) * 1.2 + (seed - 0.5) * 0.6;
              const speed = 140 + seed * 180;
              const vx = Math.sin(ang) * speed;
              const vy = -120 - seed2 * 90;
              const wm = windMul(seed);
              const dx = vx * time + 0.5 * WIND_X * wm * 1.15 * time * time * windRamp;
              const dy = vy * time + 0.5 * GRAVITY * time * time + 0.5 * WIND_Y * wm * time * time * windRamp;
              const spin = (seed * 360) + (360 + seed * 480) * time * (seed < 0.5 ? 1 : -1);
              const pieceLen = segEnd - x0;
              greenPieces.push(
                <g key={`gp${idx}`} transform={`translate(${startX + midX + dx} ${startY + dy}) rotate(${spin})`} opacity={pieceA}>
                  <line x1={-pieceLen / 2} y1={0} x2={pieceLen / 2} y2={0}
                    stroke={CC.green} strokeWidth="2" strokeLinecap="round" />
                </g>
              );
              x0 = segEnd;
              idx++;
            }
          }

          return <g>{ringChunks}{innerChunks}{greenPieces}</g>;
        })()}

      </svg>

      {/* Center logo — two-stage pen-trace reveal */}
      <div style={{ position: 'absolute', inset: 0, pointerEvents: 'none',
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        fontFamily: "'Montserrat', sans-serif", color: CC.base }}>
        <div style={{
          transform: `translateY(${h1Y}px) scale(${logoScale})`,
          opacity: h1Out,
          width: logoWidthPct,
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          transformOrigin: 'center center',
          position: 'relative',
        }}>
          {/* Upper band: A→P monogram (top 67% of image — includes full monogram, stops before divider), left→right wipe driven by monoA */}
          <img src="assets/logo-full-white.png" alt=""
            style={{
              width: '100%', height: 'auto', display: 'block',
              clipPath: `inset(0% ${(1 - monoA) * 100}% 33% 0%)`,
              WebkitClipPath: `inset(0% ${(1 - monoA) * 100}% 33% 0%)`,
            }} />
          {/* Pen cursor for monogram */}
          {monoA > 0 && monoA < 1 && (
            <div style={{
              position: 'absolute',
              top: '0%', height: '67%',
              left: `${monoA * 100}%`,
              width: 2,
              transform: 'translateX(-1px)',
              background: `linear-gradient(to bottom,
                transparent 0%,
                rgba(246,244,239,0.0) 8%,
                rgba(246,244,239,0.85) 50%,
                rgba(246,244,239,0.0) 92%,
                transparent 100%)`,
              boxShadow: '0 0 8px rgba(246,244,239,0.6)',
            }} />
          )}
          {/* Lower band: vertical divider + AP2 | FRACTION wordmark (below monogram), left→right wipe driven by wordA */}
          <img src="assets/logo-full-white.png" alt="AP2 FRACTION"
            style={{
              position: 'absolute', inset: 0,
              width: '100%', height: 'auto', display: 'block',
              clipPath: `inset(67% ${(1 - wordA) * 100}% 0% 0%)`,
              WebkitClipPath: `inset(67% ${(1 - wordA) * 100}% 0% 0%)`,
            }} />
          {/* Pen cursor for wordmark */}
          {wordA > 0 && wordA < 1 && (
            <div style={{
              position: 'absolute',
              top: '67%', bottom: 0,
              left: `${wordA * 100}%`,
              width: 2,
              transform: 'translateX(-1px)',
              background: `linear-gradient(to bottom,
                transparent 0%,
                rgba(246,244,239,0.0) 10%,
                rgba(246,244,239,0.85) 50%,
                rgba(246,244,239,0.0) 90%,
                transparent 100%)`,
              boxShadow: '0 0 8px rgba(246,244,239,0.6)',
            }} />
          )}
        </div>
      </div>

      {/* Logo shatter layer — only visible during burst */}
      {burstT > 0 && burstT < 1 && (() => {
        const time = burstT * BURST_DUR;
        const fadeT = clamp((burstT - 0.6) / 0.4, 0, 1);
        const pieceA = 1 - fadeT;
        if (pieceA <= 0.01) return null;
        const rand = (n) => ((n * 2654435761) >>> 0) / 4294967296;

        // Logo box dims (matches the rendered <img> above)
        const logoW = (isPortrait ? 0.14 : 0.22) * W;
        const logoH = logoW * (741 / 891);
        const logoL = cx - logoW / 2;
        const logoT = cy - logoH / 2;

        // Grid subdivision — balanced for visual density vs perf
        const COLS = isPortrait ? 24 : 32;
        const ROWS = isPortrait ? 18 : 22;
        const cellW = logoW / COLS;
        const cellH = logoH / ROWS;

        const GRAVITY = 380;
        const WIND_X = 520;
        const WIND_Y = -180;
        const windRamp = Easing.easeOutCubic(clamp(time / 0.6, 0, 1));
        const windBase = 0.5 * WIND_X * time * time * windRamp;
        const windBaseY = 0.5 * WIND_Y * time * time * windRamp;
        const gravTerm = 0.5 * GRAVITY * time * time;

        const pieces = [];
        const bgSize = `${logoW}px ${logoH}px`;
        for (let r = 0; r < ROWS; r++) {
          for (let c = 0; c < COLS; c++) {
            const idx = r * COLS + c;
            const seed = rand(idx * 13 + 7);
            const seed2 = rand(idx * 41 + 19);
            // Piece original center in scene coords
            const px = logoL + c * cellW + cellW / 2;
            const py = logoT + r * cellH + cellH / 2;
            // Direction outward from logo center, with jitter
            const dx0 = px - cx;
            const dy0 = py - cy;
            const baseAng = Math.atan2(dy0, dx0);
            const ang = baseAng + (seed - 0.5) * 0.8;
            const speed = 180 + seed * 320;
            const wm = 0.55 + seed2 * 0.9 + Math.sin(time * 3 + seed2 * 10) * 0.15;
            const dx = Math.cos(ang) * speed * time + windBase * wm;
            const dy = Math.sin(ang) * speed * time - 60 * time + gravTerm + windBaseY * wm;
            const spin = (seed2 - 0.5) * 720 * time * (1 + seed);
            pieces.push(
              <div key={idx} style={{
                position: 'absolute',
                left: 0, top: 0,
                width: cellW, height: cellH,
                transform: `translate3d(${px - cellW / 2 + dx}px, ${py - cellH / 2 + dy}px, 0) rotate(${spin}deg)`,
                backgroundImage: 'url(assets/logo-full-white.png)',
                backgroundSize: bgSize,
                backgroundPosition: `${-c * cellW}px ${-r * cellH}px`,
                borderRadius: '50%',
                opacity: pieceA,
              }} />
            );
          }
        }
        return <div style={{ position: 'absolute', inset: 0, pointerEvents: 'none', willChange: 'contents' }}>{pieces}</div>;
      })()}
    </div>
  );
}

Object.assign(window, { Scene });
