import { interpolate, spring, useCurrentFrame, useVideoConfig } from 'remotion';

/**
 * Kinetic-typography subtitle overlay.
 *
 * Designed to layer ON TOP of the existing scenes — they continue running
 * underneath, and these captions ride the lower third (or any chosen Y)
 * to fill what would otherwise be "hold" moments where the scene's
 * animation has ended but the voice-over keeps going.
 *
 * Curation principle: only key emphasis phrases get captioned, never the
 * full voice-over. Pulled from the Apple / Linear / Stripe playbook —
 * captions punctuate, they don't transcribe.
 *
 * Word-by-word entrance: each word springs up from +16px with a tight
 * damped spring at a 4-frame stagger. Whole-line exit fade over 14
 * frames. Rendering is gated by `local < -6 || local > durationFrames+6`
 * so the component returns null outside its window — keeps the render
 * tree slim even when twelve captions are scheduled.
 *
 * Typography:
 *   - `variant='sans'`: ui-sans-serif stack, weight 700, tightened tracking
 *   - `variant='mono'`: ui-monospace stack, weight 700, neutral tracking —
 *     use for technical labels like `AES-256` or `OAuth 2.1 + PKCE` so
 *     they read as terms rather than prose
 *
 * Size tiers (1080p reference):
 *   - `lg`      54px — default body caption
 *   - `xl`      76px — emphasis lines that should hit hard
 *   - `display` 104px — closing-shot hero text ("Live server out.")
 *
 * Positioning is from-top percentage. Default 84% sits the caption in the
 * lower third without colliding with most scene content. For the closing
 * display-size line set `yPercent` to 50 so it lands centred.
 */
interface SubtitleProps {
  text: string;
  /** Global frame at which the entrance begins. */
  startFrame: number;
  /** Total visible frames including entrance + hold + 14-frame exit. */
  durationFrames: number;
  variant?: 'sans' | 'mono';
  size?: 'lg' | 'xl' | 'display';
  /** Y position as % from top of the 1920×1080 frame. Default 84 (lower third). */
  yPercent?: number;
}

const WORD_STAGGER = 4;
const EXIT_FRAMES = 14;

export function Subtitle({
  text,
  startFrame,
  durationFrames,
  variant = 'sans',
  size = 'lg',
  yPercent = 84,
}: SubtitleProps) {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();
  const local = frame - startFrame;

  // Bail out cheap when off-screen. The 6-frame envelope on each side
  // covers the spring overshoot at entrance + exit so we don't blink.
  if (local < -6 || local > durationFrames + 6) return null;

  const words = text.split(' ');

  const exitT = interpolate(
    local,
    [durationFrames - EXIT_FRAMES, durationFrames],
    [1, 0],
    { extrapolateLeft: 'clamp', extrapolateRight: 'clamp' },
  );

  const fontPx = size === 'display' ? 104 : size === 'xl' ? 76 : 54;
  const yPx = (yPercent / 100) * 1080;

  const fontFamily =
    variant === 'mono'
      ? 'ui-monospace, SF Mono, Menlo, monospace'
      : 'ui-sans-serif, system-ui, -apple-system, sans-serif';

  const letterSpacing =
    size === 'display' ? '-0.025em' : variant === 'mono' ? '0' : '-0.015em';

  return (
    <div
      aria-hidden
      style={{
        position: 'absolute',
        left: 0,
        right: 0,
        top: yPx,
        textAlign: 'center',
        pointerEvents: 'none',
        fontFamily,
        fontSize: fontPx,
        fontWeight: 700,
        letterSpacing,
        lineHeight: 1.08,
        color: '#fafafa',
        // Drop-shadow blurs the text against whatever scene paint sits
        // behind it; the tiny indigo glow ties the type to the brand
        // without making the caption itself look colored.
        textShadow:
          '0 2px 24px rgba(0, 0, 0, 0.55), 0 0 1px rgba(99, 102, 241, 0.22)',
        opacity: exitT,
        padding: '0 6%',
      }}
    >
      {words.map((word, i) => {
        const wordEnter = i * WORD_STAGGER;
        const t = spring({
          frame: local - wordEnter,
          fps,
          config: { damping: 18, mass: 0.5, stiffness: 140 },
          durationInFrames: 16,
        });
        return (
          <span
            key={`${word}-${i}`}
            style={{
              display: 'inline-block',
              transform: `translateY(${(1 - t) * 16}px)`,
              opacity: t,
              marginRight: '0.28em',
            }}
          >
            {word}
          </span>
        );
      })}
    </div>
  );
}
