/* global React */
// Subtle interactive background — slow drifting nodes that respond to mouse position.
// Stays well behind content (low z-index, low opacity).

const BackgroundCanvas = () => {
  const canvasRef = React.useRef(null);
  const mouseRef = React.useRef({ x: -9999, y: -9999, active: false });

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

    let W = 0, H = 0;
    let raf;

    const resize = () => {
      W = window.innerWidth;
      H = window.innerHeight;
      canvas.width = W * dpr;
      canvas.height = H * dpr;
      canvas.style.width = W + "px";
      canvas.style.height = H + "px";
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
    };
    resize();

    // Particle count scales with viewport area — but stays modest
    const area = W * H;
    const COUNT = Math.min(80, Math.max(28, Math.floor(area / 28000)));
    const particles = Array.from({ length: COUNT }, () => ({
      x: Math.random() * W,
      y: Math.random() * H,
      vx: (Math.random() - 0.5) * 0.12,
      vy: (Math.random() - 0.5) * 0.12,
      r: 0.6 + Math.random() * 1.4,
      seed: Math.random() * Math.PI * 2,
    }));

    const onMouse = (e) => {
      mouseRef.current.x = e.clientX;
      mouseRef.current.y = e.clientY;
      mouseRef.current.active = true;
    };
    const onLeave = () => { mouseRef.current.active = false; };
    const onTouch = (e) => {
      if (e.touches && e.touches[0]) {
        mouseRef.current.x = e.touches[0].clientX;
        mouseRef.current.y = e.touches[0].clientY;
        mouseRef.current.active = true;
      }
    };

    window.addEventListener("mousemove", onMouse, { passive: true });
    window.addEventListener("mouseout", onLeave, { passive: true });
    window.addEventListener("touchmove", onTouch, { passive: true });
    window.addEventListener("resize", resize);

    let last = performance.now();
    const INFLUENCE = 180; // px — mouse influence radius
    const CONNECT_DIST = 130; // px — line connection radius

    const tick = (t) => {
      const dt = Math.min((t - last) / 16.67, 3); // frames since last (capped)
      last = t;

      ctx.clearRect(0, 0, W, H);

      const m = mouseRef.current;

      // Update + draw nodes
      for (const p of particles) {
        // Idle drift with gentle sine
        p.x += p.vx * dt;
        p.y += p.vy * dt;
        p.x += Math.sin(t / 4000 + p.seed) * 0.05;
        p.y += Math.cos(t / 4500 + p.seed * 1.3) * 0.05;

        // Wrap
        if (p.x < -10) p.x = W + 10;
        if (p.x > W + 10) p.x = -10;
        if (p.y < -10) p.y = H + 10;
        if (p.y > H + 10) p.y = -10;

        // Mouse push (very subtle)
        if (m.active && !reduceMotion) {
          const dx = p.x - m.x;
          const dy = p.y - m.y;
          const d2 = dx * dx + dy * dy;
          if (d2 < INFLUENCE * INFLUENCE) {
            const d = Math.sqrt(d2);
            const f = (1 - d / INFLUENCE) * 0.35;
            p.x += (dx / d) * f * dt;
            p.y += (dy / d) * f * dt;
          }
        }
      }

      // Draw connections (O(n^2) but n is small)
      ctx.lineWidth = 0.6;
      for (let i = 0; i < particles.length; i++) {
        const a = particles[i];
        for (let j = i + 1; j < particles.length; j++) {
          const b = particles[j];
          const dx = a.x - b.x;
          const dy = a.y - b.y;
          const d2 = dx * dx + dy * dy;
          if (d2 < CONNECT_DIST * CONNECT_DIST) {
            const d = Math.sqrt(d2);
            const alpha = (1 - d / CONNECT_DIST) * 0.16;
            ctx.strokeStyle = `oklch(0.62 0.16 295 / ${alpha})`;
            ctx.beginPath();
            ctx.moveTo(a.x, a.y);
            ctx.lineTo(b.x, b.y);
            ctx.stroke();
          }
        }
      }

      // Draw mouse-cursor influence halo
      if (m.active && !reduceMotion) {
        const grad = ctx.createRadialGradient(m.x, m.y, 0, m.x, m.y, INFLUENCE * 1.4);
        grad.addColorStop(0, "oklch(0.55 0.18 295 / 0.18)");
        grad.addColorStop(0.5, "oklch(0.55 0.18 295 / 0.04)");
        grad.addColorStop(1, "oklch(0.55 0.18 295 / 0)");
        ctx.fillStyle = grad;
        ctx.beginPath();
        ctx.arc(m.x, m.y, INFLUENCE * 1.4, 0, Math.PI * 2);
        ctx.fill();
      }

      // Draw nodes on top of lines
      for (const p of particles) {
        let extraGlow = 0;
        if (m.active && !reduceMotion) {
          const dx = p.x - m.x;
          const dy = p.y - m.y;
          const d2 = dx * dx + dy * dy;
          if (d2 < INFLUENCE * INFLUENCE) {
            extraGlow = 1 - Math.sqrt(d2) / INFLUENCE;
          }
        }
        // Halo for nodes near cursor
        if (extraGlow > 0.05) {
          const haloR = p.r * 6 + extraGlow * 8;
          const g2 = ctx.createRadialGradient(p.x, p.y, 0, p.x, p.y, haloR);
          g2.addColorStop(0, `oklch(0.72 0.2 295 / ${0.25 * extraGlow})`);
          g2.addColorStop(1, "oklch(0.72 0.2 295 / 0)");
          ctx.fillStyle = g2;
          ctx.beginPath();
          ctx.arc(p.x, p.y, haloR, 0, Math.PI * 2);
          ctx.fill();
        }
        // Node core
        ctx.fillStyle = `oklch(0.7 0.15 295 / ${0.35 + extraGlow * 0.55})`;
        ctx.beginPath();
        ctx.arc(p.x, p.y, p.r + extraGlow * 0.6, 0, Math.PI * 2);
        ctx.fill();
      }

      raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);

    // Pause when tab hidden
    const onVis = () => {
      if (document.hidden) {
        cancelAnimationFrame(raf);
      } else {
        last = performance.now();
        raf = requestAnimationFrame(tick);
      }
    };
    document.addEventListener("visibilitychange", onVis);

    return () => {
      cancelAnimationFrame(raf);
      window.removeEventListener("mousemove", onMouse);
      window.removeEventListener("mouseout", onLeave);
      window.removeEventListener("touchmove", onTouch);
      window.removeEventListener("resize", resize);
      document.removeEventListener("visibilitychange", onVis);
    };
  }, []);

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

window.BackgroundCanvas = BackgroundCanvas;
