function DigitalRain({ intensity = 1, accent = true, paused = false, inverted = false }) {
  const canvasRef = React.useRef(null);
  const rafRef = React.useRef(null);
  const stateRef = React.useRef({ columns: [], w: 0, h: 0, dpr: 1 });
  const propsRef = React.useRef({ intensity, accent, paused, inverted });
  propsRef.current = { intensity, accent, paused, inverted };

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

    const glyphs = 'ｱｲｳｴｵｶｷｸｹｺｻｼｽｾｿﾀﾁﾂﾃﾄﾅﾆﾇﾈﾉﾊﾋﾌﾍﾎﾏﾐﾑﾒﾓﾔﾕﾖﾗﾘﾙﾚﾛﾜｦﾝ01010110'.split('');
    const fontSize = 16;

    const resize = () => {
      const dpr = Math.min(window.devicePixelRatio || 1, 2);
      const w = canvas.clientWidth;
      const h = canvas.clientHeight;
      if (w === 0 || h === 0) return;
      canvas.width = w * dpr;
      canvas.height = h * dpr;
      // Reset transform so scale doesn't compound between resizes
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
      const colCount = Math.max(1, Math.floor(w / fontSize));
      const prev = stateRef.current.columns;
      const columns = [];
      for (let i = 0; i < colCount; i++) {
        const old = prev[i];
        columns.push(old || {
          y: Math.random() * h,
          speed: 0.4 + Math.random() * 1.6,
          length: 8 + Math.floor(Math.random() * 24),
        });
      }
      stateRef.current = { columns, w, h, dpr };
    };

    resize();
    const ro = new ResizeObserver(resize);
    ro.observe(canvas);
    window.addEventListener('resize', resize);

    let lastTime = performance.now();
    const draw = (t) => {
      const dt = Math.min(50, t - lastTime);
      lastTime = t;
      const p = propsRef.current;
      if (p.paused) {
        rafRef.current = requestAnimationFrame(draw);
        return;
      }

      const { columns, w, h } = stateRef.current;
      if (!w || !h) {
        rafRef.current = requestAnimationFrame(draw);
        return;
      }

      // Fade — direction depends on inverted mode
      ctx.fillStyle = p.inverted ? 'rgba(255,255,255,0.09)' : 'rgba(0,0,0,0.09)';
      ctx.fillRect(0, 0, w, h);

      ctx.font = `${fontSize}px "Geist Mono", monospace`;
      ctx.textBaseline = 'top';

      const headColor = p.inverted ? '#000000' : '#ffffff';
      const trailBase = p.inverted ? '30,30,30' : '220,220,220';

      for (let i = 0; i < columns.length; i++) {
        const col = columns[i];
        const x = i * fontSize;
        col.y += col.speed * (dt / 16) * p.intensity;

        const headChar = glyphs[Math.floor(Math.random() * glyphs.length)];
        const rareGreen = p.accent && Math.random() < 0.0008;
        ctx.fillStyle = rareGreen ? '#6fcf2b' : headColor;
        ctx.fillText(headChar, x, col.y);

        for (let j = 1; j < col.length; j++) {
          const y = col.y - j * fontSize;
          if (y < -fontSize || y > h) continue;
          const alpha = Math.max(0, (1 - j / col.length) * 0.8);
          ctx.fillStyle = `rgba(${trailBase},${alpha})`;
          const ch = glyphs[Math.floor((Math.random() * glyphs.length + i + j) % glyphs.length)];
          ctx.fillText(ch, x, y);
        }

        if (col.y - col.length * fontSize > h) {
          col.y = -Math.random() * h * 0.5;
          col.speed = 0.4 + Math.random() * 1.6;
          col.length = 8 + Math.floor(Math.random() * 24);
        }
      }

      rafRef.current = requestAnimationFrame(draw);
    };

    rafRef.current = requestAnimationFrame(draw);
    return () => {
      cancelAnimationFrame(rafRef.current);
      ro.disconnect();
      window.removeEventListener('resize', resize);
    };
  }, []); // mount-once; props read via propsRef

  return <canvas ref={canvasRef} className="rain-canvas" />;
}

window.DigitalRain = DigitalRain;
