import { useCurrentFrame, useVideoConfig, interpolate } from 'remotion';
import { C } from '../lib/colors';
import { rand, clampLerp, easeInOut, softSpring } from '../lib/easings';
import { BEAT } from '../HeroVideo';

// Beat 2 — the wow moment.
//
// Prompt words detonate into ~60 chunky glowing particles that drift, then
// magnetically snap into target slots along a SERVER SCHEMATIC. The
// schematic strokes on IN PARALLEL with the convergence so the eye always
// has something to anchor to — earlier versions had a dead frame ~3s in
// where particles were too small and the box hadn't drawn yet.

const PARTICLE_COUNT = 60;

const SERVER_W = 720;
const SERVER_H = 420;
const CX = 960;
const CY = 540;

function targetSlot(i: number) {
  const N = PARTICLE_COUNT;
  if (i < N / 2) {
    // perimeter walk
    const t = i / (N / 2);
    const perim = 2 * (SERVER_W + SERVER_H);
    const d = t * perim;
    const left = CX - SERVER_W / 2;
    const top = CY - SERVER_H / 2;
    let px = left;
    let py = top;
    if (d < SERVER_W) { px = left + d; py = top; }
    else if (d < SERVER_W + SERVER_H) { px = left + SERVER_W; py = top + (d - SERVER_W); }
    else if (d < 2 * SERVER_W + SERVER_H) { px = left + SERVER_W - (d - SERVER_W - SERVER_H); py = top + SERVER_H; }
    else { px = left; py = top + SERVER_H - (d - 2 * SERVER_W - SERVER_H); }
    return { x: px, y: py };
  }
  // Inside the box: three tool rows
  const j = i - N / 2;
  const perRow = Math.ceil(N / 2 / 3);
  const row = Math.floor(j / perRow);
  const col = (j % perRow) / Math.max(1, perRow - 1);
  const rowY = CY - 90 + row * 90;
  const rowX = CX - SERVER_W / 2 + 50 + col * (SERVER_W - 100);
  return { x: rowX, y: rowY };
}

export function TransformScene() {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();
  const local = frame - BEAT.transform.in;

  const sceneIn = clampLerp(frame, BEAT.transform.in, BEAT.transform.in + 6);
  const sceneOut = 1 - clampLerp(frame, BEAT.transform.out - 8, BEAT.transform.out);
  const sceneAlpha = Math.min(sceneIn, sceneOut);

  // Schematic strokes on IN PARALLEL with the convergence — starts at
  // local 8 instead of 30 so the box is visible before particles arrive.
  const strokeT = easeInOut(clampLerp(local, 8, 55));
  // Ports + rows show up as schematic completes
  const innerT = clampLerp(local, 35, 65);
  const portPulse = clampLerp(local, 55, 90);

  // Scan-line — diagonal pass once the schematic is fully drawn
  const scanT = clampLerp(local, 55, 90);

  // Central core glow — visible throughout Beat 2 so the eye has an
  // anchor even when particles are mid-flight. Pulses softly.
  const coreAlpha = clampLerp(local, 0, 12) * (1 - clampLerp(local, 95, 110) * 0.4);
  const corePulse = 1 + 0.25 * Math.sin(local * 0.18);

  return (
    <div style={{ position: 'absolute', inset: 0, opacity: sceneAlpha }}>
      {/* Central core — radial glow that's always-on during Beat 2. Sells
          "something is building here" before the schematic is drawn. */}
      <div
        style={{
          position: 'absolute',
          left: CX - 200,
          top: CY - 200,
          width: 400,
          height: 400,
          background: `radial-gradient(circle, ${C.accentGlow} 0%, transparent 60%)`,
          opacity: coreAlpha * 0.7,
          transform: `scale(${corePulse})`,
          pointerEvents: 'none',
        }}
      />

      {/* Particles — 60 chunky glowing dots */}
      <svg width={1920} height={1080} style={{ position: 'absolute', inset: 0 }}>
        <defs>
          <filter id="glow" x="-50%" y="-50%" width="200%" height="200%">
            <feGaussianBlur stdDeviation="2.5" result="blur" />
            <feMerge>
              <feMergeNode in="blur" />
              <feMergeNode in="SourceGraphic" />
            </feMerge>
          </filter>
        </defs>
        {Array.from({ length: PARTICLE_COUNT }).map((_, i) => {
          const wordIndex = i % 4;
          const wordX = 760 + wordIndex * 130 + rand(i * 7.13) * 60 - 30;
          const wordY = 540 + rand(i * 3.71) * 24 - 12;

          const slot = targetSlot(i);
          // Velocity vectors — particles fly outward in a roughly radial
          // pattern from the prompt baseline. Magnitude varied per particle.
          const angle = rand(i * 1.71) * Math.PI * 2;
          const speed = 240 + rand(i * 4.13) * 380;
          const vx = Math.cos(angle) * speed;
          const vy = Math.sin(angle) * speed - 60; // bias slightly upward

          const explode = clampLerp(local, 0, 18);
          // Pull starts earlier (frame 14 instead of 25) so particles
          // are visible converging rather than just drifting.
          const pull = softSpring(frame, fps, BEAT.transform.in + 14, 42);

          const driftX = wordX + vx * explode * (1 - pull);
          const driftY = wordY + vy * explode * (1 - pull);
          const x = driftX + (slot.x - driftX) * pull;
          const y = driftY + (slot.y - driftY) * pull;

          // Radius: 6→3 as particles lock in. Big enough at 1080p that
          // every particle is clearly visible.
          const r = interpolate(pull, [0, 1], [6, 3]);
          // Always indigo — earlier two-color split was indecisive
          const color = C.accent;
          const alpha = clampLerp(local, 0, 4);
          const fadeOut = 1 - clampLerp(local, 88, 108) * 0.4;

          return (
            <circle
              key={i}
              cx={x}
              cy={y}
              r={r}
              fill={color}
              opacity={alpha * fadeOut * 0.95}
              filter="url(#glow)"
            />
          );
        })}
      </svg>

      {/* Server schematic */}
      <svg
        width={1920}
        height={1080}
        style={{ position: 'absolute', inset: 0, pointerEvents: 'none' }}
      >
        <defs>
          <linearGradient id="scanline" x1="0%" y1="0%" x2="100%" y2="100%">
            <stop offset={`${Math.max(0, scanT * 100 - 6)}%`} stopColor={C.accent} stopOpacity="0" />
            <stop offset={`${scanT * 100}%`} stopColor={C.accent} stopOpacity="0.95" />
            <stop offset={`${Math.min(100, scanT * 100 + 6)}%`} stopColor={C.accent} stopOpacity="0" />
          </linearGradient>
        </defs>

        {/* Faint inner panel as the box draws — gives volume immediately */}
        <rect
          x={CX - SERVER_W / 2}
          y={CY - SERVER_H / 2}
          width={SERVER_W}
          height={SERVER_H}
          rx={8}
          fill={C.bgElevated}
          opacity={strokeT * 0.5}
        />

        {/* Outer rectangle stroke */}
        <rect
          x={CX - SERVER_W / 2}
          y={CY - SERVER_H / 2}
          width={SERVER_W}
          height={SERVER_H}
          rx={8}
          fill="none"
          stroke={C.accent}
          strokeWidth={3}
          strokeDasharray={2 * (SERVER_W + SERVER_H)}
          strokeDashoffset={(1 - strokeT) * 2 * (SERVER_W + SERVER_H)}
          opacity={0.95}
          style={{ filter: `drop-shadow(0 0 8px ${C.accentGlow})` }}
        />

        {/* Three internal tool rows */}
        {[0, 1, 2].map((r) => {
          const y = CY - 90 + r * 90;
          return (
            <g key={r} opacity={innerT}>
              <line
                x1={CX - SERVER_W / 2 + 40}
                y1={y}
                x2={CX + SERVER_W / 2 - 40}
                y2={y}
                stroke={C.borderStrong}
                strokeWidth={1.5}
              />
              <circle cx={CX - SERVER_W / 2 + 50} cy={y} r={5} fill={C.accent} opacity={0.95}
                style={{ filter: `drop-shadow(0 0 4px ${C.accentGlow})` }}
              />
            </g>
          );
        })}

        {/* Port dots */}
        {[-1, 1].map((side) =>
          [-1, 0, 1].map((off) => (
            <circle
              key={`${side}-${off}`}
              cx={CX + (SERVER_W / 2) * side}
              cy={CY + off * 90}
              r={6}
              fill={C.accent}
              opacity={portPulse * (0.7 + 0.3 * Math.sin(local * 0.3 + off))}
              style={{ filter: `drop-shadow(0 0 8px ${C.accentGlow})` }}
            />
          )),
        )}

        {/* Scan-line sweep */}
        {scanT > 0 && scanT < 1 && (
          <rect
            x={CX - SERVER_W / 2}
            y={CY - SERVER_H / 2}
            width={SERVER_W}
            height={SERVER_H}
            rx={8}
            fill="url(#scanline)"
            opacity={0.65}
          />
        )}
      </svg>

      {/* Corner labels — bigger and earlier */}
      <CornerLabel x={CX - SERVER_W / 2} y={CY - SERVER_H / 2 - 36} text="mcp-notion" appearAt={local} delay={42} />
      <CornerLabel x={CX + SERVER_W / 2} y={CY - SERVER_H / 2 - 36} text="OAuth 2.1" appearAt={local} delay={48} align="right" />
      <CornerLabel x={CX - SERVER_W / 2} y={CY + SERVER_H / 2 + 16} text="search_pages" appearAt={local} delay={54} />
      <CornerLabel x={CX + SERVER_W / 2} y={CY + SERVER_H / 2 + 16} text="get_page_content" appearAt={local} delay={60} align="right" />
    </div>
  );
}

function CornerLabel({
  x, y, text, appearAt, delay, align = 'left',
}: {
  x: number; y: number; text: string; appearAt: number; delay: number; align?: 'left' | 'right';
}) {
  const t = clampLerp(appearAt, delay, delay + 8);
  return (
    <div
      style={{
        position: 'absolute',
        left: align === 'left' ? x : undefined,
        right: align === 'right' ? 1920 - x : undefined,
        top: y,
        fontFamily: 'ui-monospace, SF Mono, Menlo, monospace',
        fontSize: 17,
        letterSpacing: '0.08em',
        color: C.fgMuted,
        opacity: t,
        transform: `translateY(${(1 - t) * 4}px)`,
      }}
    >
      {text}
    </div>
  );
}
