// FallingSymbols — canvas of ASCII block glyphs falling down with glitch-swap.
// Palette-tuned defaults match the cream/terracotta/navy site.

const FallingSymbols = ({
  symbols = '░▒▓█▌▐',
  symbolColors,
  fontSize = 16,
  backgroundColor,
  glitchSpeed = 80,
  glitchIntensity = 0.03,
  fallSpeed = 0.7,
  outerVignette = true,
  style,
}) => {
  const canvasRef = React.useRef(null);
  const containerRef = React.useRef(null);
  const rafRef = React.useRef(0);
  const gridRef = React.useRef({ columns: 0, rows: 0, charWidth: 0, charHeight: 0 });
  const lettersRef = React.useRef([]);
  const lastGlitchRef = React.useRef(0);

  // Palette defaults aligned with site colors
  const bg = backgroundColor || (typeof C !== 'undefined' ? C.cream : '#F4EEE0');
  const colors = symbolColors || [
    'rgba(232, 93, 58, 0.55)',   // terracotta
    'rgba(43, 58, 95, 0.48)',    // navy
    'rgba(26, 24, 21, 0.32)',    // ink
    'rgba(154, 147, 133, 0.38)', // inkMute
    'rgba(232, 93, 58, 0.28)',
  ];

  const pickChar = React.useCallback(() => symbols[Math.floor(Math.random() * symbols.length)], [symbols]);
  const pickColor = React.useCallback(() => colors[Math.floor(Math.random() * colors.length)], [colors]);

  React.useEffect(() => {
    const canvas = canvasRef.current;
    const container = containerRef.current;
    if (!canvas || !container) return;
    const ctx = canvas.getContext('2d');
    if (!ctx) return;

    let W = 0, H = 0;

    const setup = () => {
      if (rafRef.current) cancelAnimationFrame(rafRef.current);
      const dpr = Math.min(window.devicePixelRatio || 1, 2);
      const rect = container.getBoundingClientRect();
      W = rect.width; H = rect.height;
      canvas.width = Math.max(1, Math.floor(W * dpr));
      canvas.height = Math.max(1, Math.floor(H * dpr));
      canvas.style.width = W + 'px';
      canvas.style.height = H + 'px';
      ctx.setTransform(1, 0, 0, 1, 0, 0);
      ctx.scale(dpr, dpr);
      ctx.font = `${fontSize}px ui-monospace, "SF Mono", Menlo, monospace`;
      ctx.textBaseline = 'top';

      const m = ctx.measureText('M');
      const cw = m.width;
      const ch = fontSize * 1.2;
      const cols = Math.max(1, Math.floor(W / cw));
      const rows = Math.max(1, Math.floor(H / ch));
      gridRef.current = { columns: cols, rows, charWidth: cw, charHeight: ch };

      const extRows = rows * 2;
      const total = cols * extRows;
      lettersRef.current = Array.from({ length: total }, (_, i) => {
        const col = i % cols;
        const row = Math.floor(i / cols);
        return {
          char: pickChar(),
          x: col * cw,
          y: row * ch - rows * ch,
          color: pickColor(),
        };
      });

      rafRef.current = requestAnimationFrame(animate);
    };

    const animate = (ts) => {
      rafRef.current = requestAnimationFrame(animate);

      if (ts - lastGlitchRef.current > glitchSpeed) {
        lastGlitchRef.current = ts;
        const n = Math.floor(lettersRef.current.length * glitchIntensity);
        for (let i = 0; i < n; i++) {
          const idx = Math.floor(Math.random() * lettersRef.current.length);
          const L = lettersRef.current[idx];
          if (L) { L.char = pickChar(); L.color = pickColor(); }
        }
      }

      const fieldH = gridRef.current.rows * gridRef.current.charHeight * 2;
      for (const L of lettersRef.current) {
        L.y += fallSpeed;
        if (L.y > H) L.y -= fieldH;
      }

      ctx.fillStyle = bg;
      ctx.fillRect(0, 0, W, H);

      ctx.font = `${fontSize}px ui-monospace, "SF Mono", Menlo, monospace`;
      ctx.textBaseline = 'top';
      for (const L of lettersRef.current) {
        ctx.fillStyle = L.color;
        ctx.fillText(L.char, L.x, L.y);
      }
    };

    let t;
    const onResize = () => { clearTimeout(t); t = setTimeout(setup, 150); };
    window.addEventListener('resize', onResize);
    const ro = new ResizeObserver(() => { clearTimeout(t); t = setTimeout(setup, 150); });
    ro.observe(container);
    setup();

    return () => {
      window.removeEventListener('resize', onResize);
      ro.disconnect();
      if (rafRef.current) cancelAnimationFrame(rafRef.current);
    };
  }, [symbols, bg, fontSize, glitchSpeed, glitchIntensity, fallSpeed, pickChar, pickColor]);

  return (
    <div
      ref={containerRef}
      style={{
        position: 'absolute', inset: 0,
        width: '100%', height: '100%',
        overflow: 'hidden',
        ...style,
      }}
    >
      <canvas ref={canvasRef} style={{ position: 'absolute', inset: 0 }} />
      {outerVignette && (
        <div style={{
          position: 'absolute', inset: 0, pointerEvents: 'none',
          background: 'radial-gradient(circle, transparent 55%, rgba(244,238,224,0.85) 100%)',
        }} />
      )}
    </div>
  );
};

window.FallingSymbols = FallingSymbols;
