/* global React */
// Animated network/nodes background for hero
// Uses canvas + requestAnimationFrame. Dark / light aware.

const { useEffect, useRef } = React;

function NetworkCanvas({ density = 1, speedMul = 1, full = true }) {
  const canvasRef = useRef(null);
  const rafRef = useRef(0);

  useEffect(() => {
    const canvas = canvasRef.current;
    const ctx = canvas.getContext("2d");
    let DPR = Math.min(window.devicePixelRatio || 1, 2);
    let width = 0, height = 0;
    let nodes = [];
    let mouse = { x: -9999, y: -9999, active: false };

    const computeAccent = () => {
      const dark = document.documentElement.dataset.theme === "dark";
      return dark
        ? { line: "rgba(34, 211, 238, ALPHA)", dot: "rgba(180, 230, 250, ALPHA)", glow: "rgba(34, 211, 238, 0.18)" }
        : { line: "rgba(8, 145, 178, ALPHA)", dot: "rgba(10, 31, 61, ALPHA)", glow: "rgba(6, 182, 212, 0.10)" };
    };

    let palette = computeAccent();

    const resize = () => {
      const parent = canvas.parentElement;
      width = parent.clientWidth;
      height = parent.clientHeight;
      canvas.width = width * DPR;
      canvas.height = height * DPR;
      canvas.style.width = width + "px";
      canvas.style.height = height + "px";
      ctx.setTransform(DPR, 0, 0, DPR, 0, 0);

      const base = full ? 0.00009 : 0.00018;
      const count = Math.round(width * height * base * density);
      nodes = new Array(count).fill(0).map(() => ({
        x: Math.random() * width,
        y: Math.random() * height,
        vx: (Math.random() - 0.5) * 0.25 * speedMul,
        vy: (Math.random() - 0.5) * 0.25 * speedMul,
        r: Math.random() * 1.4 + 0.6,
      }));
    };

    const onMouse = (e) => {
      const rect = canvas.getBoundingClientRect();
      mouse.x = e.clientX - rect.left;
      mouse.y = e.clientY - rect.top;
      mouse.active = true;
    };
    const onLeave = () => { mouse.active = false; mouse.x = -9999; mouse.y = -9999; };

    const themeObserver = new MutationObserver(() => { palette = computeAccent(); });
    themeObserver.observe(document.documentElement, { attributes: true, attributeFilter: ["data-theme"] });

    const draw = () => {
      ctx.clearRect(0, 0, width, height);

      // Move nodes
      for (const n of nodes) {
        n.x += n.vx;
        n.y += n.vy;
        if (n.x < -20) n.x = width + 20;
        if (n.x > width + 20) n.x = -20;
        if (n.y < -20) n.y = height + 20;
        if (n.y > height + 20) n.y = -20;

        // Repel from mouse
        if (mouse.active) {
          const dx = n.x - mouse.x;
          const dy = n.y - mouse.y;
          const d2 = dx * dx + dy * dy;
          if (d2 < 14400) {
            const f = (1 - d2 / 14400) * 0.6;
            n.x += (dx / Math.sqrt(d2 + 0.01)) * f;
            n.y += (dy / Math.sqrt(d2 + 0.01)) * f;
          }
        }
      }

      // Lines
      const maxDist = full ? 140 : 110;
      for (let i = 0; i < nodes.length; i++) {
        const a = nodes[i];
        for (let j = i + 1; j < nodes.length; j++) {
          const b = nodes[j];
          const dx = a.x - b.x;
          const dy = a.y - b.y;
          const dist = Math.sqrt(dx * dx + dy * dy);
          if (dist < maxDist) {
            const alpha = (1 - dist / maxDist) * 0.45;
            ctx.strokeStyle = palette.line.replace("ALPHA", alpha.toFixed(3));
            ctx.lineWidth = 0.7;
            ctx.beginPath();
            ctx.moveTo(a.x, a.y);
            ctx.lineTo(b.x, b.y);
            ctx.stroke();
          }
        }
      }

      // Dots
      for (const n of nodes) {
        ctx.fillStyle = palette.dot.replace("ALPHA", "0.7");
        ctx.beginPath();
        ctx.arc(n.x, n.y, n.r, 0, Math.PI * 2);
        ctx.fill();
      }

      // Mouse glow
      if (mouse.active) {
        const grad = ctx.createRadialGradient(mouse.x, mouse.y, 0, mouse.x, mouse.y, 160);
        grad.addColorStop(0, palette.glow);
        grad.addColorStop(1, "transparent");
        ctx.fillStyle = grad;
        ctx.fillRect(0, 0, width, height);
      }

      rafRef.current = requestAnimationFrame(draw);
    };

    const ro = new ResizeObserver(resize);
    ro.observe(canvas.parentElement);
    resize();

    if (!window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
      window.addEventListener("mousemove", onMouse);
      window.addEventListener("mouseleave", onLeave);
      draw();
    } else {
      // Static frame
      draw();
      cancelAnimationFrame(rafRef.current);
    }

    return () => {
      cancelAnimationFrame(rafRef.current);
      ro.disconnect();
      themeObserver.disconnect();
      window.removeEventListener("mousemove", onMouse);
      window.removeEventListener("mouseleave", onLeave);
    };
  }, [density, speedMul, full]);

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

window.NetworkCanvas = NetworkCanvas;
