// ParticleField — cinematic particle background.
// Performance pass: removed per-particle radial gradients (expensive),
// using flat dots + single shadow pass instead. DPR capped at 1.5.
// Connection lines use bbox pre-check and lower connect radius.

function ParticleField({ density = 55, hue = "cool", interactive = true }) {
  const ref = React.useRef(null);
  const mouse = React.useRef({ x: 0.5, y: 0.5, active: false });

  React.useEffect(() => {
    const canvas = ref.current;
    if (!canvas) return;
    const ctx = canvas.getContext("2d");
    let raf = null, particles = [], w = 0, h = 0;
    // Cap DPR — halves pixel fill on retina, negligible visual difference
    const dpr = Math.min(window.devicePixelRatio || 1, 1.5);
    let paused = document.hidden;

    const palette = hue === "warm"
      ? ["255,45,157", "107,63,255", "255,179,71"]
      : ["0,229,255", "45,111,247", "107,63,255"];

    function resize() {
      const r = canvas.getBoundingClientRect();
      w = r.width; h = r.height;
      canvas.width = w * dpr; canvas.height = h * dpr;
      ctx.scale(dpr, dpr);
      const count = Math.min(density, window.innerWidth < 768 ? 28 : density);
      particles = Array.from({ length: count }, () => ({
        x: Math.random() * w, y: Math.random() * h,
        bvx: (Math.random() - 0.5) * 0.14,
        bvy: (Math.random() - 0.5) * 0.14,
        vx: 0, vy: 0,
        r: Math.random() * 1.5 + 0.4,
        c: palette[Math.floor(Math.random() * palette.length)],
        a: Math.random() * 0.45 + 0.20,
      }));
    }
    resize();
    window.addEventListener("resize", resize);

    function onMove(e) {
      const r = canvas.getBoundingClientRect();
      mouse.current.x = (e.clientX - r.left) / r.width;
      mouse.current.y = (e.clientY - r.top) / r.height;
      mouse.current.active = true;
    }
    if (interactive) window.addEventListener("mousemove", onMove);

    const CONNECT = 90; // reduced connection radius — fewer lines
    const DAMP = 0.960;

    function tick() {
      if (paused) { raf = null; return; }
      ctx.clearRect(0, 0, w, h);
      const mx = mouse.current.x * w, my = mouse.current.y * h;
      const R = 150;

      // Move particles
      for (const p of particles) {
        if (interactive && mouse.current.active) {
          const dx = p.x - mx, dy = p.y - my, d = Math.hypot(dx, dy) || 0.0001;
          if (d < R) {
            const force = (1 - d / R) * 0.8;
            p.vx += (dx / d) * force;
            p.vy += (dy / d) * force;
          }
        }
        p.x += p.bvx + p.vx;
        p.y += p.bvy + p.vy;
        p.vx *= DAMP; p.vy *= DAMP;
        if (p.x < 0) p.x = w; if (p.x > w) p.x = 0;
        if (p.y < 0) p.y = h; if (p.y > h) p.y = 0;
      }

      // Draw particles — flat dot + single shadowBlur pass (no per-particle gradient)
      ctx.shadowBlur = 12;
      for (const p of particles) {
        ctx.shadowColor = `rgba(${p.c},0.55)`;
        ctx.fillStyle   = `rgba(${p.c},${p.a})`;
        ctx.beginPath();
        ctx.arc(p.x, p.y, p.r, 0, Math.PI * 2);
        ctx.fill();
      }
      ctx.shadowBlur = 0;

      // Connection lines — bbox guard eliminates most distance checks
      ctx.lineWidth = 0.45;
      for (let i = 0; i < particles.length; i++) {
        for (let j = i + 1; j < particles.length; j++) {
          const a = particles[i], b = particles[j];
          const dx = a.x - b.x;
          if (dx > CONNECT || dx < -CONNECT) continue;
          const dy = a.y - b.y;
          if (dy > CONNECT || dy < -CONNECT) continue;
          const d = Math.hypot(dx, dy);
          if (d < CONNECT) {
            ctx.strokeStyle = `rgba(${a.c},${((1 - d / CONNECT) * 0.10).toFixed(3)})`;
            ctx.beginPath(); ctx.moveTo(a.x, a.y); ctx.lineTo(b.x, b.y); ctx.stroke();
          }
        }
      }
      raf = requestAnimationFrame(tick);
    }

    const onVis = () => {
      paused = document.hidden;
      if (!paused && !raf) tick();
    };
    document.addEventListener("visibilitychange", onVis);
    tick();

    return () => {
      if (raf) cancelAnimationFrame(raf);
      window.removeEventListener("resize", resize);
      if (interactive) window.removeEventListener("mousemove", onMove);
      document.removeEventListener("visibilitychange", onVis);
    };
  }, [density, hue, interactive]);

  return (
    <canvas ref={ref}
      style={{ position: "absolute", inset: 0, width: "100%", height: "100%", pointerEvents: "none" }} />
  );
}

window.ParticleField = ParticleField;
