/* global React, window, document */
const { useRef: useRefMesh, useEffect: useEffectMesh } = React;

/* Plano de pontos do hero: superfície distante que flutua como seda, em uma
   faixa full-bleed abaixo do texto. Pontos pretos sobre o cream, com fade no
   topo (horizonte) e no rodapé. Config por breakpoint: desktop fica como está,
   mobile é afinado para ler como o desktop (superfície longa em perspectiva). */

const CFG_DESKTOP = {
  cols: 240, rows: 92, ampFactor: 0.34,
  sizeBase: 0.35, sizeGain: 1.5,
  powExp: 1.42, spreadBase: 1.3, spreadGain: 0.95,
  bfadeStart: 1.06, bfadeEnd: 0.72,
  horizonF: 0.06, alphaCap: 0.6, nearExtent: 1.06,
};
const CFG_MOBILE = {
  cols: 150, rows: 150, ampFactor: 0.17,
  sizeBase: 0.3, sizeGain: 1.15,
  powExp: 1.42, spreadBase: 1.05, spreadGain: 1.0,
  bfadeStart: 1.3, bfadeEnd: 1.12,
  horizonF: 0.05, alphaCap: 0.58, nearExtent: 1.24,
};

function HeroMesh() {
  const canvasRef = useRefMesh(null);

  useEffectMesh(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const ctx = canvas.getContext('2d');
    const reduced = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
    let W = 0, H = 0, dpr = 1, t = 0, raf = 0, running = true, cfg = CFG_DESKTOP;

    const smooth = (a, b, x) => { const k = Math.min(1, Math.max(0, (x - a) / (b - a))); return k * k * (3 - 2 * k); };

    function resize() {
      const rect = canvas.getBoundingClientRect();
      W = rect.width; H = rect.height;
      dpr = Math.min(window.devicePixelRatio || 1, 2);
      canvas.width = Math.round(W * dpr);
      canvas.height = Math.round(H * dpr);
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
      cfg = W < 700 ? CFG_MOBILE : CFG_DESKTOP;
    }

    /* Campo independente da resolução: coordenadas normalizadas (un, v) com
       frequências fixas calibradas no desktop (REFI/REFJ), então o padrão de
       ondas é o mesmo em qualquer cols/rows. No desktop dá idêntico ao anterior. */
    const REFI = 240, REFJ = 92;
    function field(un, v, time) {
      const i = un * REFI, j = v * REFJ;
      return (
        0.50 * Math.sin(i * 0.13 + j * 0.05 - time * 0.55) +
        0.42 * Math.sin(i * 0.06 - j * 0.17 + time * 0.40) +
        0.30 * Math.sin((i + j) * 0.10 + time * 0.32) +
        0.24 * Math.sin(i * 0.27 - j * 0.23 + time * 0.72) +
        0.16 * Math.sin((i - j) * 0.19 + time * 0.90)
      ) / 1.45;
    }

    function draw() {
      ctx.clearRect(0, 0, W, H);
      ctx.fillStyle = '#141414';
      const cols = cfg.cols, rows = cfg.rows;
      const horizon = H * cfg.horizonF;
      const amp = H * cfg.ampFactor;
      const TWO_PI = 6.283185;
      for (let j = 0; j <= rows; j++) {
        const d = j / rows;
        const rowY = horizon + (H * cfg.nearExtent - horizon) * Math.pow(d, cfg.powExp);
        const persp = 0.18 + 0.82 * d;
        const baseSize = cfg.sizeBase + cfg.sizeGain * d;
        const vfade = smooth(0.0, 0.16, d);
        const bfade = smooth(cfg.bfadeStart, cfg.bfadeEnd, rowY / H);
        let rowAlpha = (0.05 + 0.5 * d) * vfade * bfade;
        if (rowAlpha < 0.012) continue;
        ctx.globalAlpha = Math.min(cfg.alphaCap, rowAlpha);
        ctx.beginPath();
        for (let i = 0; i <= cols; i++) {
          const u = i / cols - 0.5;
          const x = W / 2 + u * W * (cfg.spreadBase + cfg.spreadGain * d);
          if (x < -10 || x > W + 10) continue;
          const hgt = field(i / cols, d, t);
          const y = rowY - hgt * amp * persp;
          if (y < -10 || y > H + 10) continue;
          const peak = (hgt + 1) / 2;
          const size = baseSize * (0.7 + 0.55 * peak);
          ctx.moveTo(x + size, y);
          ctx.arc(x, y, size, 0, TWO_PI);
        }
        ctx.fill();
      }
      ctx.globalAlpha = 1;
    }

    function frame() { if (!running) return; t += 0.016; draw(); raf = window.requestAnimationFrame(frame); }
    function start() { if (raf || reduced) return; running = true; raf = window.requestAnimationFrame(frame); }
    function stop() { running = false; if (raf) { window.cancelAnimationFrame(raf); raf = 0; } }

    resize();
    draw();
    const onResize = () => { resize(); draw(); };
    window.addEventListener('resize', onResize);
    const onVis = () => { if (document.hidden) stop(); else start(); };
    document.addEventListener('visibilitychange', onVis);
    let io = null;
    if ('IntersectionObserver' in window) {
      io = new IntersectionObserver((es) => { es.forEach((e) => { if (e.isIntersecting) start(); else stop(); }); }, { threshold: 0 });
      io.observe(canvas);
    }
    if (!reduced) start();

    return () => { stop(); window.removeEventListener('resize', onResize); document.removeEventListener('visibilitychange', onVis); if (io) io.disconnect(); };
  }, []);

  return <canvas ref={canvasRef} aria-hidden="true" style={{ display: 'block', width: '100%', height: '100%' }} />;
}

window.HeroMesh = HeroMesh;
