/* ============================================================
   combo.codes — LetterGlitch background (interactive spotlight)
   Canvas port of the reactbits.dev "Letter Glitch" effect,
   naturalized to the combo.codes palette: the code field sits
   GREY at rest, and lights up in brand colors under the cursor
   like a torch. Exposed on window.LetterGlitch.
   Pure presentation — no logic.
   ============================================================ */
function LetterGlitch({
  baseColors,
  highlightColors,
  interactive = true,
  spotlightRadius = 150,
  glitchSpeed = 70,
  smooth = true,
  outerVignette = true,
  centerVignette = true,
  className = '',
  style = {},
}) {
  const canvasRef = React.useRef(null);
  const animationRef = React.useRef(null);
  const letters = React.useRef([]);
  const grid = React.useRef({ columns: 0, rows: 0 });
  const context = React.useRef(null);
  const lastGlitchTime = React.useRef(Date.now());
  const mouse = React.useRef({ x: -9999, y: -9999, active: false, dirty: false });

  const fontSize = 16;
  const charWidth = 10;
  const charHeight = 20;

  const GLYPHS = [
    'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
    '0','1','2','3','4','5','6','7','8','9',
    '{','}','(',')','[',']','<','>','/','\\',';',':','.',',','=','+','-','*','_','!','?','#','$','%','&','@','|','~','^',
  ];

  const bases = baseColors && baseColors.length ? baseColors : ['#33303C', '#3E3A48', '#4A4555', '#565061'];
  const glows = highlightColors && highlightColors.length ? highlightColors : ['#A855F7', '#C8FF2E', '#2FE6FF'];

  const pick = (arr) => arr[Math.floor(Math.random() * arr.length)];
  const getRandomChar = () => GLYPHS[Math.floor(Math.random() * GLYPHS.length)];

  const hexToRgb = (hex) => {
    const shorthand = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
    hex = hex.replace(shorthand, (m, r, g, b) => r + r + g + g + b + b);
    const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
    return result
      ? { r: parseInt(result[1], 16), g: parseInt(result[2], 16), b: parseInt(result[3], 16) }
      : { r: 80, g: 76, b: 92 };
  };
  const rgbStr = (c) => 'rgb(' + c.r + ', ' + c.g + ', ' + c.b + ')';
  const mix = (start, end, factor) => ({
    r: Math.round(start.r + (end.r - start.r) * factor),
    g: Math.round(start.g + (end.g - start.g) * factor),
    b: Math.round(start.b + (end.b - start.b) * factor),
  });

  const calculateGrid = (width, height) => ({
    columns: Math.ceil(width / charWidth),
    rows: Math.ceil(height / charHeight),
  });

  const initializeLetters = (columns, rows) => {
    grid.current = { columns, rows };
    const total = columns * rows;
    letters.current = Array.from({ length: total }, () => {
      const base = pick(bases);
      return {
        char: getRandomChar(),
        base: base,
        baseRgb: hexToRgb(base),
        glowRgb: hexToRgb(pick(glows)),
        targetRgb: hexToRgb(base),
        colorProgress: 1,
      };
    });
  };

  const resizeCanvas = () => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const parent = canvas.parentElement;
    if (!parent) return;
    const dpr = window.devicePixelRatio || 1;
    const rect = parent.getBoundingClientRect();
    canvas.width = rect.width * dpr;
    canvas.height = rect.height * dpr;
    canvas.style.width = rect.width + 'px';
    canvas.style.height = rect.height + 'px';
    if (context.current) context.current.setTransform(dpr, 0, 0, dpr, 0, 0);
    const { columns, rows } = calculateGrid(rect.width, rect.height);
    initializeLetters(columns, rows);
    drawLetters();
  };

  const drawLetters = () => {
    if (!context.current || letters.current.length === 0) return;
    const ctx = context.current;
    const rect = canvasRef.current.getBoundingClientRect();
    ctx.clearRect(0, 0, rect.width, rect.height);
    ctx.font = fontSize + 'px ui-monospace, monospace';
    ctx.textBaseline = 'top';

    const m = mouse.current;
    const lit = interactive && m.active;
    const r = spotlightRadius;
    const cols = grid.current.columns;

    letters.current.forEach((letter, index) => {
      const col = index % cols;
      const row = (index - col) / cols;
      const x = col * charWidth;
      const y = row * charHeight;

      let color = letter.targetRgb;
      if (lit) {
        const dx = x + charWidth / 2 - m.x;
        const dy = y + charHeight / 2 - m.y;
        const dist = Math.sqrt(dx * dx + dy * dy);
        if (dist < r) {
          let f = 1 - dist / r;
          f = f * f * (3 - 2 * f); // smoothstep: bright, generous core; soft edge
          color = mix(letter.targetRgb, letter.glowRgb, f);
        }
      }
      ctx.fillStyle = rgbStr(color);
      ctx.fillText(letter.char, x, y);
    });
  };

  const updateLetters = () => {
    if (!letters.current || letters.current.length === 0) return;
    const updateCount = Math.max(1, Math.floor(letters.current.length * 0.05));
    for (let i = 0; i < updateCount; i++) {
      const index = Math.floor(Math.random() * letters.current.length);
      const l = letters.current[index];
      if (!l) continue;
      l.char = getRandomChar();
      const next = hexToRgb(pick(bases));
      l.glowRgb = hexToRgb(pick(glows));
      if (!smooth) {
        l.baseRgb = next;
        l.targetRgb = next;
        l.colorProgress = 1;
      } else {
        l.baseRgb = l.targetRgb;
        l.target = next;
        l.targetRgb0 = l.targetRgb;
        l._to = next;
        l.colorProgress = 0;
      }
    }
  };

  // advance grey<->grey crossfades; returns true if anything changed
  const advanceSmooth = () => {
    let changed = false;
    letters.current.forEach((letter) => {
      if (letter.colorProgress < 1 && letter._to) {
        letter.colorProgress += 0.05;
        if (letter.colorProgress > 1) letter.colorProgress = 1;
        letter.targetRgb = mix(letter.baseRgb, letter._to, letter.colorProgress);
        changed = true;
      }
    });
    return changed;
  };

  const animate = () => {
    const now = Date.now();
    let draw = false;
    if (now - lastGlitchTime.current >= glitchSpeed) {
      updateLetters();
      lastGlitchTime.current = now;
      draw = true;
    }
    if (smooth && advanceSmooth()) draw = true;
    if (mouse.current.dirty) { draw = true; mouse.current.dirty = false; }
    if (draw) drawLetters();
    animationRef.current = requestAnimationFrame(animate);
  };

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

    const reduce = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
    if (!reduce) animate();
    else drawLetters();

    const onMove = (e) => {
      const rect = canvas.getBoundingClientRect();
      mouse.current.x = e.clientX - rect.left;
      mouse.current.y = e.clientY - rect.top;
      mouse.current.active = true;
      mouse.current.dirty = true;
      if (reduce) drawLetters();
    };
    const onLeave = () => {
      mouse.current.active = false;
      mouse.current.dirty = true;
      if (reduce) drawLetters();
    };

    if (interactive) {
      window.addEventListener('pointermove', onMove, { passive: true });
      window.addEventListener('pointerdown', onMove, { passive: true });
      window.addEventListener('blur', onLeave);
      document.addEventListener('mouseleave', onLeave);
    }

    let timeout;
    const handleResize = () => {
      cancelAnimationFrame(animationRef.current);
      clearTimeout(timeout);
      timeout = setTimeout(() => {
        resizeCanvas();
        if (!reduce) animate();
      }, 120);
    };
    window.addEventListener('resize', handleResize);

    return () => {
      cancelAnimationFrame(animationRef.current);
      clearTimeout(timeout);
      window.removeEventListener('resize', handleResize);
      window.removeEventListener('pointermove', onMove);
      window.removeEventListener('pointerdown', onMove);
      window.removeEventListener('blur', onLeave);
      document.removeEventListener('mouseleave', onLeave);
    };
  }, [glitchSpeed, smooth, interactive, spotlightRadius, JSON.stringify(bases), JSON.stringify(glows)]);

  return (
    <div className={'letterglitch ' + className} style={style}>
      <canvas ref={canvasRef} className="letterglitch__canvas"></canvas>
      {outerVignette ? <div className="letterglitch__vignette letterglitch__vignette--outer"></div> : null}
      {centerVignette ? <div className="letterglitch__vignette letterglitch__vignette--center"></div> : null}
    </div>
  );
}

window.LetterGlitch = LetterGlitch;
