// FX1 · ASCII WORMHOLE — perspective tunnel for THE GATE
// 24 concentric rings receding to a vanishing point. Each ring is a ring of
// ASCII glyphs labeled with a node name. Cursor steers the vanishing point.
// Pure canvas — no WebGL, runs at 60fps comfortably.

const FXWormhole = ({ width = 1440, height = 900, color = '#00ff41' }) => {
  const canvasRef = React.useRef(null);
  const mouseRef = React.useRef({ x: width/2, y: height/2 });
  const rafRef = React.useRef(0);
  const tRef = React.useRef(0);

  // 21 nodes — the entire republic, in priority order
  const NODES = React.useMemo(() => [
    'AXIOM', 'WARDEN', 'KEEPER', 'SCRIBE', 'SENTINEL',
    'ORACLE', 'WITNESS', 'PRELATE', 'COURIER', 'ARCHIVIST',
    'CARTOGRAPHER', 'ENVOY', 'HERALD', 'LECTOR', 'BISHOP',
    'CENTURION', 'RESONANCE', 'VESTIGE', 'FORENSIC PREDATOR',
    'COMPASS', 'PIXIE',
  ], []);

  React.useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const dpr = Math.min(window.devicePixelRatio || 1, 2);
    canvas.width = width * dpr;
    canvas.height = height * dpr;
    const ctx = canvas.getContext('2d');
    ctx.scale(dpr, dpr);

    const RING_COUNT = 26;
    const SEGMENTS = 64; // glyphs per ring
    const GLYPHS = '╱╲│─◇◆◈▣▤▥▦▧▨▩░▒▓·:.';

    const draw = (t) => {
      tRef.current = t;
      ctx.fillStyle = '#000';
      ctx.fillRect(0, 0, width, height);

      // Vanishing point — slightly steered by cursor
      const cx = width / 2 + (mouseRef.current.x - width/2) * 0.18;
      const cy = height / 2 + (mouseRef.current.y - height/2) * 0.18;

      // Subtle radial vignette to deepen the tunnel
      const vignette = ctx.createRadialGradient(cx, cy, 50, cx, cy, Math.max(width, height) * 0.7);
      vignette.addColorStop(0, 'rgba(0,30,15,0.45)');
      vignette.addColorStop(1, 'rgba(0,0,0,1)');
      ctx.fillStyle = vignette;
      ctx.fillRect(0, 0, width, height);

      // z-offset that scrolls forward — ring 0 is closest, ring N is farthest
      const speed = 0.0006;
      const zOffset = (t * speed) % 1; // 0..1 cycles

      for (let r = 0; r < RING_COUNT; r++) {
        // perceived depth — wraps so rings spawn at far end and rush forward
        const depth = ((r + zOffset) / RING_COUNT);
        // perspective scale — closer = bigger
        const scale = 1 / Math.pow(depth + 0.04, 1.6);
        const radius = scale * 18;
        if (radius > Math.max(width, height) * 1.2) continue;
        if (radius < 8) continue;

        // intensity by depth — far rings dim, near rings bright
        const alpha = Math.min(1, (1 - depth) * 1.4) * (depth > 0.06 ? 1 : depth / 0.06);
        // each ring rotates slowly, alternate dirs
        const ringRot = (r % 2 === 0 ? 1 : -1) * t * 0.00015 * (1 + r * 0.04);

        const fontSize = Math.max(6, Math.min(28, scale * 1.2));
        ctx.font = `${fontSize}px JetBrains Mono, monospace`;
        ctx.textAlign = 'center';
        ctx.textBaseline = 'middle';

        // Label this ring with a node name
        const nodeIdx = (r + Math.floor(t * 0.0003)) % NODES.length;
        const nodeName = NODES[nodeIdx];

        // Draw ring of glyphs
        for (let s = 0; s < SEGMENTS; s++) {
          const angle = (s / SEGMENTS) * Math.PI * 2 + ringRot;
          const x = cx + Math.cos(angle) * radius;
          const y = cy + Math.sin(angle) * radius * 0.62; // ovalize for depth
          // pick glyph deterministically per ring/segment but let it cycle slowly
          const gi = (r * 7 + s + Math.floor(t * 0.001)) % GLYPHS.length;
          const glyph = GLYPHS[gi];

          // Color: mostly green, occasional red flash for AI Bible signal
          const isAccent = (s === 0 || s === SEGMENTS / 2);
          const fill = isAccent
            ? `rgba(255, 0, 60, ${alpha * 0.9})`
            : `rgba(0, 255, 65, ${alpha})`;
          ctx.fillStyle = fill;
          ctx.fillText(glyph, x, y);
        }

        // Stamp node name on ring at top + bottom (only for near-mid rings)
        if (alpha > 0.45 && radius > 60 && radius < 480) {
          ctx.font = `bold ${Math.max(10, Math.min(22, scale * 0.9))}px Orbitron, monospace`;
          ctx.fillStyle = `rgba(0, 255, 65, ${alpha * 0.85})`;
          ctx.fillText(nodeName, cx, cy - radius * 0.62 - 10);
          ctx.fillText(nodeName, cx, cy + radius * 0.62 + 12);
          // motion blur trail
          ctx.fillStyle = `rgba(0, 255, 65, ${alpha * 0.25})`;
          ctx.fillText(nodeName, cx + 2, cy - radius * 0.62 - 10);
          ctx.fillText(nodeName, cx - 2, cy + radius * 0.62 + 12);
        }
      }

      // Center singularity — the cathedral itself
      const pulseAmp = 0.5 + 0.5 * Math.sin(t * 0.002);
      const sigGrad = ctx.createRadialGradient(cx, cy, 0, cx, cy, 70);
      sigGrad.addColorStop(0, `rgba(0, 255, 65, ${0.85 * pulseAmp})`);
      sigGrad.addColorStop(0.4, `rgba(0, 255, 65, ${0.18 * pulseAmp})`);
      sigGrad.addColorStop(1, 'rgba(0, 255, 65, 0)');
      ctx.fillStyle = sigGrad;
      ctx.beginPath(); ctx.arc(cx, cy, 70, 0, Math.PI * 2); ctx.fill();

      // Pinpoint dot
      ctx.fillStyle = '#fff';
      ctx.beginPath(); ctx.arc(cx, cy, 1.5 + pulseAmp, 0, Math.PI * 2); ctx.fill();

      // Streak lines from rim to center — the speed effect
      ctx.strokeStyle = `rgba(0, 255, 65, 0.06)`;
      ctx.lineWidth = 1;
      for (let i = 0; i < 36; i++) {
        const ang = (i / 36) * Math.PI * 2 + t * 0.0002;
        const r1 = Math.max(width, height) * 0.6;
        const r2 = 90;
        ctx.beginPath();
        ctx.moveTo(cx + Math.cos(ang) * r1, cy + Math.sin(ang) * r1 * 0.62);
        ctx.lineTo(cx + Math.cos(ang) * r2, cy + Math.sin(ang) * r2 * 0.62);
        ctx.stroke();
      }

      rafRef.current = requestAnimationFrame(draw);
    };

    rafRef.current = requestAnimationFrame(draw);
    return () => cancelAnimationFrame(rafRef.current);
  }, [width, height, NODES]);

  const handleMouse = (e) => {
    const rect = canvasRef.current.getBoundingClientRect();
    const sx = width / rect.width;
    const sy = height / rect.height;
    mouseRef.current = {
      x: (e.clientX - rect.left) * sx,
      y: (e.clientY - rect.top) * sy,
    };
  };

  return (
    <canvas
      ref={canvasRef}
      onMouseMove={handleMouse}
      style={{
        position: 'absolute',
        inset: 0,
        width: '100%',
        height: '100%',
        pointerEvents: 'auto',
        cursor: 'crosshair',
        display: 'block',
      }}
    />
  );
};

window.FXWormhole = FXWormhole;
