// GlitchText — scramble-decode text effect that fires on first viewport enter.
// Locks characters left-to-right at a steady cadence; non-letter chars (spaces,
// punctuation) lock immediately so words stay legible during the decode.
const GLITCH_CHARS = '!<>-_\\/[]{}—=+*^?#0123456789ABCDEFGHJKLMNPQRSTUVWXYZ';

function GlitchText({ text, className, durationMs = 700, lockStaggerMs = 32 }) {
  const ref = React.useRef(null);
  const [out, setOut] = React.useState(text);

  React.useEffect(() => {
    const node = ref.current;
    if (!node || !text) return;
    const reduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
    if (reduced) { setOut(text); return; }

    const chars = Array.from(text);
    let played = false;
    let raf = 0;
    let timeout = 0;

    function play() {
      if (played) return;
      played = true;
      const start = performance.now();
      const lockTimes = chars.map((c, i) => /\s/.test(c) ? 0 : i * lockStaggerMs + 60);

      function tick(now) {
        const elapsed = now - start;
        let allDone = true;
        const next = chars.map((c, i) => {
          if (/[\s ]/.test(c)) return c;
          if (elapsed >= lockTimes[i]) return c;
          allDone = false;
          return GLITCH_CHARS[(Math.random() * GLITCH_CHARS.length) | 0];
        });
        setOut(next.join(''));
        if (!allDone && elapsed < durationMs + chars.length * lockStaggerMs) {
          raf = requestAnimationFrame(tick);
        } else {
          setOut(text);
        }
      }
      raf = requestAnimationFrame(tick);
    }

    const obs = new IntersectionObserver((entries) => {
      for (const e of entries) {
        if (e.isIntersecting) {
          // Tiny delay so it feels like the section is "decoding in"
          timeout = setTimeout(play, 80);
          obs.disconnect();
          break;
        }
      }
    }, { threshold: 0.2 });
    obs.observe(node);

    return () => {
      obs.disconnect();
      cancelAnimationFrame(raf);
      clearTimeout(timeout);
    };
  }, [text, durationMs, lockStaggerMs]);

  return (
    <span ref={ref} className={(className || '') + ' glitch-text'} aria-label={text}>
      {out}
    </span>
  );
}

window.GlitchText = GlitchText;
