/* eslint-disable */
// Flowing "cloth of dots" for the hero (2D canvas).
// A regular lattice of points displaced by a smooth low-frequency noise field
// so neighbours move together and the grid ripples like fabric. Crests of the
// height field glow brighter. The pointer adds a damped ripple that pushes and
// lights up nearby dots. Exported as window.HeroLiquid so app.jsx is untouched.

function HeroParticles() {
  const ref = React.useRef(null);

  React.useEffect(() => {
    const canvas = ref.current;
    if (!canvas) return;
    const ctx = canvas.getContext('2d');
    const dpr = Math.min(window.devicePixelRatio || 1, 2);
    const reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;

    // --- cheap value noise (bilinear, smoothed) ---
    const hash = (x, y) => {
      const h = Math.sin(x * 127.1 + y * 311.7) * 43758.5453;
      return h - Math.floor(h);
    };
    const smooth = (t) => t * t * (3 - 2 * t);
    const noise = (x, y) => {
      const xi = Math.floor(x), yi = Math.floor(y);
      const xf = x - xi, yf = y - yi;
      const a = hash(xi, yi),     b = hash(xi + 1, yi);
      const c = hash(xi, yi + 1), d = hash(xi + 1, yi + 1);
      const u = smooth(xf), v = smooth(yf);
      return a + (b - a) * u + (c - a) * v + (a - b - c + d) * u * v;
    };
    const clamp01 = (x) => x < 0 ? 0 : x > 1 ? 1 : x;

    const SP = 24; // lattice spacing (screen px)
    let W = 0, H = 0;
    const resize = () => {
      const r = canvas.getBoundingClientRect();
      W = Math.max(1, Math.floor(r.width));
      H = Math.max(1, Math.floor(r.height));
      canvas.width = Math.floor(W * dpr);
      canvas.height = Math.floor(H * dpr);
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
    };
    resize();
    const ro = new ResizeObserver(resize);
    ro.observe(canvas);

    let mx = -9999, my = -9999, tmx = -9999, tmy = -9999, has = false;
    const onMove = (e) => {
      const r = canvas.getBoundingClientRect();
      tmx = e.clientX - r.left;
      tmy = e.clientY - r.top;
      if (!has) { mx = tmx; my = tmy; }
      has = true;
    };
    const onLeave = (e) => { if (!e.relatedTarget && !e.toElement) has = false; };
    window.addEventListener('mousemove', onMove, { passive: true });
    window.addEventListener('mouseout', onLeave);

    const R = 195; // pointer influence radius
    let raf = 0;
    const t0 = performance.now();

    const frame = (now) => {
      const ts = reduce ? 6 : (now - t0) / 1000;
      if (has) { mx += (tmx - mx) * 0.12; my += (tmy - my) * 0.12; }

      ctx.clearRect(0, 0, W, H);
      const fx = 0.0017, fy = 0.0023;
      const flow = ts * 0.10;

      for (let gy = -SP; gy <= H + SP; gy += SP) {
        // vertical fade: ease in from the top, out toward the bottom seam
        const fade = clamp01(gy / 140) * (1 - clamp01((gy - (H - 170)) / 170));
        if (fade <= 0) continue;

        for (let gx = -SP; gx <= W + SP; gx += SP) {
          const a  = noise(gx * fx + flow,        gy * fy);
          const b  = noise(gx * fx + 7.3,         gy * fy - flow);
          const hh = noise(gx * fx * 0.7 + flow * 0.8 + 3.1, gy * fy * 0.7);

          let ox = (a - 0.5) * SP * 1.7;
          let oy = (b - 0.5) * SP * 1.3;
          let alpha = 0.09 + smooth(clamp01((hh - 0.42) / 0.40)) * 0.66; // crests glow
          let rad = 0.55 + hh * 1.15;

          if (has) {
            const ddx = (gx + ox) - mx, ddy = (gy + oy) - my;
            const d = Math.sqrt(ddx * ddx + ddy * ddy);
            if (d < R) {
              const f = 1 - d / R;
              const inv = 1 / (d + 1e-3);
              const wave = Math.sin(d * 0.05 - ts * 3.0);
              ox += ddx * inv * f * 24 * (0.6 + 0.4 * wave);
              oy += ddy * inv * f * 24 * (0.6 + 0.4 * wave);
              alpha = clamp01(alpha + f * 0.45);
              rad += f * 1.3;
            }
          }

          alpha *= fade;
          if (alpha <= 0.02) continue;
          ctx.globalAlpha = alpha;
          ctx.fillStyle = '#e6e9f7';
          ctx.beginPath();
          ctx.arc(gx + ox, gy + oy, rad, 0, 6.2832);
          ctx.fill();
        }
      }
      ctx.globalAlpha = 1;
      if (!reduce) raf = requestAnimationFrame(frame);
    };
    raf = requestAnimationFrame(frame);

    return () => {
      cancelAnimationFrame(raf);
      ro.disconnect();
      window.removeEventListener('mousemove', onMove);
      window.removeEventListener('mouseout', onLeave);
    };
  }, []);

  return <canvas ref={ref} className="hero-liquid-canvas" aria-hidden="true" />;
}

window.HeroParticles = HeroParticles;
window.HeroLiquid = HeroParticles;
