import React, { useMemo } from 'react';
import { SeasonalOverlayProps } from '../types';
import {
  animGridScroll,
  animScanRoll,
  animScreenGlow,
  animCrtFlicker,
  animChromaShift,
  animSparkleDrift,
  animSparkleTwinkle,
  animCoinBlink,
  animScoreBlip,
} from './Arcade.css';

/**
 * ArcadeOverlay — retro synthwave CRT.
 *
 * A full-screen, pointer-events:none ambient decoration. The parent supplies a
 * fixed inset:0 overflow:hidden pointer-events:none container at the correct
 * z-index, so this component only returns absolutely-positioned aria-hidden
 * children and never sets position:fixed / z-index / pointer-events.
 *
 * Composition (back to front):
 *   1. near-black synthwave ambient wash (magenta sky-glow up top, cyan/purple
 *      pool toward the floor) — layered oklch gradients for depth
 *   2. a neon perspective grid receding to a vanishing point on the horizon,
 *      scrolling toward the viewer via transform translateY (never bg-position)
 *   3. a soft horizon sun-glow + thin neon horizon line where the grid meets sky
 *   4. drifting pixel sparkles / neon coin-burst specks rising off the grid
 *   5. fine CRT scanlines, gently rolling
 *   6. a faint chromatic-aberration fringe at the screen edges
 *   7. a glowing "INSERT COIN" blip + a corner SCORE HUD glyph
 *   8. a CRT vignette + screen-glow that frames and protects central text
 *
 * All motion is transform/opacity only (compositor-friendly). When `reduced` is
 * true we render a static-but-gorgeous scene: a still neon grid, steady
 * scanlines + vignette, and a steady "INSERT COIN" — no `animation` anywhere,
 * no flicker. The settings preview always passes reduced=true, so the still
 * form stands on its own.
 */

// Synthwave neon palette in oklch. Saturated where it glows, but every layer is
// held at low opacity so it tints rather than takes over the chat beneath.
const NEON_MAGENTA = 'oklch(0.65 0.25 350)';
const NEON_CYAN = 'oklch(0.80 0.15 200)';
const GRID_PURPLE = 'oklch(0.45 0.18 300)';

// The receding grid as an inline SVG data-URI (CSP-safe, no external assets).
// It is a 1x2 vertical tile of horizontal rule lines + a single set of vertical
// lines fanning toward a top-center vanishing point. The plane is then placed
// under a CSS `perspective` rotateX so the lines genuinely recede. Scrolling the
// tile up by one tile-height (animGridScroll → translateY 50%) loops seamlessly.
function gridDataUri(): string {
  const lines: string[] = [];
  // Horizontal rules — denser toward the top (the horizon) for a perspective
  // feel even before the CSS rotateX is applied.
  const rows = [0, 16, 34, 54, 76, 100, 126, 156, 190, 228, 270, 316, 366, 420, 478, 540];
  rows.forEach((y) => {
    lines.push(
      `<line x1='0' y1='${y}' x2='600' y2='${y}' stroke='${GRID_PURPLE}' ` +
        `stroke-width='1.4' stroke-opacity='0.9'/>`,
    );
  });
  // Vertical lines fanning out from the top-center vanishing point.
  for (let i = -7; i <= 7; i += 1) {
    const topX = 300 + i * 6; // tight near the horizon
    const botX = 300 + i * 95; // wide at the foreground
    lines.push(
      `<line x1='${topX}' y1='0' x2='${botX}' y2='600' stroke='${GRID_PURPLE}' ` +
        `stroke-width='1.4' stroke-opacity='0.8'/>`,
    );
  }
  const svg =
    `<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 600 600' ` +
    `preserveAspectRatio='none'>${lines.join('')}</svg>`;
  return `url("data:image/svg+xml,${encodeURIComponent(svg)}")`;
}

type Sparkle = {
  left: number; // vw
  bottom: number; // % up from floor where it spawns
  size: number; // px
  duration: number; // s
  delay: number; // s
  twinkle: number; // s
  hue: 'magenta' | 'cyan';
  opacity: number;
};

// Hand-placed still sparkles for the reduced/static scene — a few neon specks
// resting low over the grid, away from the busy chat center.
const RESTING_SPARKLES: ReadonlyArray<{
  left: number;
  bottom: number;
  size: number;
  hue: 'magenta' | 'cyan';
  opacity: number;
}> = [
  { left: 12, bottom: 18, size: 4, hue: 'cyan', opacity: 0.5 },
  { left: 26, bottom: 30, size: 3, hue: 'magenta', opacity: 0.42 },
  { left: 78, bottom: 22, size: 4, hue: 'magenta', opacity: 0.5 },
  { left: 88, bottom: 34, size: 3, hue: 'cyan', opacity: 0.4 },
  { left: 50, bottom: 14, size: 3, hue: 'cyan', opacity: 0.38 },
];

const GRID_URI = gridDataUri();

export function ArcadeOverlay({ reduced }: SeasonalOverlayProps) {
  // Deterministic sparkle field, computed ONCE. No per-frame state.
  const sparkles = useMemo<Sparkle[]>(() => {
    const COUNT = 16;
    return Array.from({ length: COUNT }, (_, i) => ({
      left: (i * 6.27 + 4) % 100,
      bottom: (i * 3.7) % 28, // spawn in the lower third (over the grid)
      size: 2 + (i % 3), // 2..4 px pixels
      duration: 14 + (i % 6) * 2.2,
      delay: -((i * 1.83) % 16),
      twinkle: 1.4 + (i % 4) * 0.5,
      hue: i % 2 === 0 ? 'cyan' : 'magenta',
      opacity: 0.45 + (i % 3) * 0.12,
    }));
  }, []);

  const sparkleColor = (hue: 'magenta' | 'cyan') => (hue === 'cyan' ? NEON_CYAN : NEON_MAGENTA);

  return (
    <>
      {/* 1. Near-black synthwave ambient wash. Magenta sky-glow up top, a
            cyan/purple pool toward the floor, and an overall dark vertical
            grade. Layered oklch gradients give depth at very low opacity. */}
      <div
        aria-hidden="true"
        style={{
          position: 'absolute',
          inset: 0,
          backgroundImage: [
            'radial-gradient(140% 80% at 50% -8%, oklch(0.65 0.25 350 / 0.16) 0%, transparent 55%)',
            'radial-gradient(120% 70% at 50% 112%, oklch(0.45 0.18 300 / 0.20) 0%, transparent 60%)',
            'linear-gradient(180deg, oklch(0.12 0.05 300 / 0.10) 0%, transparent 38%, oklch(0.10 0.06 310 / 0.16) 100%)',
          ].join(','),
          contain: 'layout paint style',
        }}
      />

      {/* 2. The neon perspective grid. A wide, tall plane is tilted away from
            the viewer with `perspective` + rotateX so its rule lines recede to
            a vanishing point at the top (the horizon). It lives in the lower
            half of the screen — the "floor". The inner plane scrolls upward by
            one tile via transform translateY, which reads as the grid flowing
            toward the viewer. Pure transform; never background-position. */}
      <div
        aria-hidden="true"
        style={{
          position: 'absolute',
          left: '-25%',
          right: '-25%',
          bottom: 0,
          height: '62%',
          overflow: 'hidden',
          perspective: '280px',
          perspectiveOrigin: '50% 0%',
          maskImage: 'linear-gradient(180deg, transparent 0%, #000 26%, #000 100%)',
          WebkitMaskImage: 'linear-gradient(180deg, transparent 0%, #000 26%, #000 100%)',
          opacity: reduced ? 0.5 : 0.62,
          contain: 'layout paint style',
        }}
      >
        <div
          style={{
            position: 'absolute',
            left: 0,
            right: 0,
            top: 0,
            height: '200%',
            transformOrigin: 'top center',
            transform: 'rotateX(74deg)',
            backgroundImage: GRID_URI,
            backgroundRepeat: 'repeat-y',
            backgroundSize: '100% 50%',
            filter: 'drop-shadow(0 0 3px oklch(0.55 0.22 320 / 0.6))',
            willChange: reduced ? undefined : 'transform',
            animation: reduced ? 'none' : `${animGridScroll} 7s linear infinite`,
          }}
        />
      </div>

      {/* 3. Horizon glow + neon horizon line. A soft synthwave sun-bloom sits
            where the grid meets the sky, with a thin bright rule on top of it
            to seal the vanishing point. Static (no motion) either way. */}
      <div
        aria-hidden="true"
        style={{
          position: 'absolute',
          left: '50%',
          top: '38%',
          width: '70%',
          height: '34%',
          transform: 'translate(-50%, -50%)',
          backgroundImage:
            'radial-gradient(60% 100% at 50% 100%, oklch(0.70 0.22 350 / 0.22) 0%, oklch(0.65 0.18 330 / 0.10) 40%, transparent 72%)',
          contain: 'layout paint style',
        }}
      />
      <div
        aria-hidden="true"
        style={{
          position: 'absolute',
          left: '12%',
          right: '12%',
          top: '38%',
          height: '1.5px',
          background: `linear-gradient(90deg, transparent 0%, ${NEON_CYAN} 25%, oklch(0.92 0.10 320 / 0.95) 50%, ${NEON_CYAN} 75%, transparent 100%)`,
          opacity: 0.55,
          filter: 'blur(0.4px) drop-shadow(0 0 4px oklch(0.78 0.16 200 / 0.7))',
        }}
      />

      {/* 4. Drifting pixel sparkles / neon coin-burst specks. Tiny square
            neon pixels rising off the grid and twinkling. The static scene uses
            a small resting set instead. */}
      {reduced
        ? RESTING_SPARKLES.map((s, i) => (
            <div
              key={`rest-spark-${i}`}
              aria-hidden="true"
              style={{
                position: 'absolute',
                left: `${s.left}%`,
                bottom: `${s.bottom}%`,
                width: `${s.size}px`,
                height: `${s.size}px`,
                background: sparkleColor(s.hue),
                opacity: s.opacity,
                boxShadow: `0 0 6px ${sparkleColor(s.hue)}`,
              }}
            />
          ))
        : sparkles.map((s, i) => (
            <div
              key={`spark-${i}`}
              aria-hidden="true"
              style={{
                position: 'absolute',
                left: `${s.left}%`,
                bottom: `${s.bottom}%`,
                width: `${s.size}px`,
                height: `${s.size}px`,
                willChange: 'transform, opacity',
                animation: `${animSparkleDrift} ${s.duration}s linear ${s.delay}s infinite`,
              }}
            >
              <div
                style={{
                  width: '100%',
                  height: '100%',
                  background: sparkleColor(s.hue),
                  opacity: s.opacity,
                  boxShadow: `0 0 6px ${sparkleColor(s.hue)}`,
                  animation: `${animSparkleTwinkle} ${s.twinkle}s step-end infinite`,
                }}
              />
            </div>
          ))}

      {/* 5. Fine CRT scanlines. A repeating 1px dark rule field over the whole
            screen, gently rolling downward on the compositor (transform only).
            Held faint so text stays crisp. The pattern is in a child taller
            than the frame so the roll never reveals an edge. */}
      <div
        aria-hidden="true"
        style={{
          position: 'absolute',
          inset: 0,
          overflow: 'hidden',
          mixBlendMode: 'multiply',
          opacity: 0.5,
          contain: 'layout paint style',
        }}
      >
        <div
          style={{
            position: 'absolute',
            left: 0,
            right: 0,
            top: '-8px',
            bottom: '-8px',
            backgroundImage:
              'repeating-linear-gradient(0deg, oklch(0.10 0.04 300 / 0.55) 0px, oklch(0.10 0.04 300 / 0.55) 1px, transparent 1px, transparent 3px)',
            willChange: reduced ? undefined : 'transform',
            animation: reduced ? 'none' : `${animScanRoll} 6s linear infinite`,
          }}
        />
      </div>

      {/* 6. Chromatic-aberration fringe. Two thin edge-glows — magenta and cyan —
            offset a sub-pixel apart at the screen border so the frame shimmers
            with an RGB split, like a misconverged tube. Animated only; in the
            static scene it sits as a steady fringe. */}
      <div
        aria-hidden="true"
        style={{
          position: 'absolute',
          inset: 0,
          boxShadow: `inset 2px 0 14px oklch(0.65 0.25 350 / 0.16), inset -2px 0 14px oklch(0.80 0.15 200 / 0.16)`,
          opacity: reduced ? 0.6 : undefined,
          willChange: reduced ? undefined : 'transform, opacity',
          contain: 'layout paint style',
          animation: reduced ? 'none' : `${animChromaShift} 4.5s ease-in-out infinite`,
        }}
      />

      {/* 7a. Glowing "INSERT COIN" attract-mode blip, low-opacity, bottom-center.
             Static scene shows it steady (no blink). */}
      <div
        aria-hidden="true"
        style={{
          position: 'absolute',
          bottom: '5%',
          left: '50%',
          transform: 'translateX(-50%)',
          fontFamily: '"Courier New", monospace',
          fontSize: '12px',
          fontWeight: 700,
          letterSpacing: '0.32em',
          color: NEON_CYAN,
          textShadow: '0 0 6px oklch(0.80 0.15 200 / 0.9), 0 0 14px oklch(0.65 0.25 350 / 0.5)',
          userSelect: 'none',
          whiteSpace: 'nowrap',
          opacity: reduced ? 0.6 : undefined,
          animation: reduced ? 'none' : `${animCoinBlink} 1.6s step-end infinite`,
        }}
      >
        INSERT COIN
      </div>

      {/* 7b. Corner SCORE HUD glyph — a tiny pixel score that blips, top-left,
             very low opacity so it reads as ambient chrome, not UI. */}
      <div
        aria-hidden="true"
        style={{
          position: 'absolute',
          top: '2.5%',
          left: '2%',
          fontFamily: '"Courier New", monospace',
          fontSize: '10px',
          fontWeight: 700,
          letterSpacing: '0.18em',
          color: NEON_MAGENTA,
          textShadow: '0 0 6px oklch(0.65 0.25 350 / 0.8)',
          userSelect: 'none',
          whiteSpace: 'nowrap',
          opacity: reduced ? 0.5 : undefined,
          animation: reduced ? 'none' : `${animScoreBlip} 2.4s ease-in-out infinite`,
        }}
      >
        1UP 00<span style={{ color: NEON_CYAN }}>0000</span>
      </div>

      {/* 8. CRT vignette + screen-glow. A radial darkening frames the corners,
            with a faint magenta tube-glow swell. The vignette protects central
            chat-text contrast. Static scene holds it steady; live scene adds a
            shallow breathing glow + irregular flicker, both opacity-only. */}
      <div
        aria-hidden="true"
        style={{
          position: 'absolute',
          inset: 0,
          backgroundImage: [
            'radial-gradient(125% 95% at 50% 46%, oklch(0.72 0.18 340 / 0.05) 0%, transparent 40%)',
            'radial-gradient(120% 115% at 50% 50%, transparent 50%, oklch(0.10 0.05 310 / 0.20) 84%, oklch(0.06 0.04 305 / 0.34) 100%)',
          ].join(','),
          contain: 'layout paint style',
          opacity: reduced ? 1 : undefined,
          willChange: reduced ? undefined : 'opacity',
          animation: reduced
            ? 'none'
            : `${animScreenGlow} 8s ease-in-out infinite, ${animCrtFlicker} 5.5s steps(1, end) infinite`,
        }}
      />
    </>
  );
}
