// Field — animated particle field that bends around cursor (gravity well)
// The signature background: thousands of subtle points, each a "data particle",
// drifting and deflecting around the pointer like iron filings.

const Field = () => {
  const canvasRef = useRef(null);
  const t = useTweaks();
  const motion = t.motion !== false;
  const intensity = t.intensity ?? 1;

  useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const ctx = canvas.getContext('2d');
    let w, h, dpr;
    let particles = [];
    let raf;

    const resize = () => {
      dpr = Math.min(window.devicePixelRatio || 1, 2);
      w = window.innerWidth;
      h = window.innerHeight;
      canvas.style.width = w + 'px';
      canvas.style.height = h + 'px';
      canvas.width = w * dpr;
      canvas.height = h * dpr;
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
      const count = Math.floor((w * h) / 9000);
      particles = Array.from({ length: count }, () => ({
        x: Math.random() * w,
        y: Math.random() * h,
        bx: 0, by: 0, // base (home) position
        vx: 0, vy: 0,
        size: Math.random() < 0.93 ? 0.7 + Math.random() * 0.6 : 1.4 + Math.random() * 0.8,
        alpha: 0.15 + Math.random() * 0.45,
        phase: Math.random() * Math.PI * 2,
        speed: 0.0003 + Math.random() * 0.0008,
        hue: Math.random() < 0.06,
      }));
      particles.forEach((p) => { p.bx = p.x; p.by = p.y; });
    };

    const draw = (ts) => {
      ctx.clearRect(0, 0, w, h);
      const m = window.__mouse__ || { x: w / 2, y: h / 2 };
      const reach = 220 * intensity;
      const reach2 = reach * reach;
      const pushStrength = 42 * intensity;

      for (const p of particles) {
        // gentle home-seeking drift
        const dx0 = p.bx - p.x;
        const dy0 = p.by - p.y;
        p.vx += dx0 * 0.0018;
        p.vy += dy0 * 0.0018;

        // cursor repulsion
        const dx = p.x - m.x;
        const dy = p.y - m.y;
        const d2 = dx * dx + dy * dy;
        if (d2 < reach2 && d2 > 1) {
          const d = Math.sqrt(d2);
          const force = (1 - d / reach) * pushStrength / d;
          p.vx += dx * force * 0.02;
          p.vy += dy * force * 0.02;
        }

        // ambient breath
        if (motion) {
          p.vx += Math.cos(ts * p.speed + p.phase) * 0.008;
          p.vy += Math.sin(ts * p.speed * 1.2 + p.phase) * 0.008;
        }

        p.vx *= 0.92;
        p.vy *= 0.92;
        p.x += p.vx;
        p.y += p.vy;

        const tw = motion ? (0.7 + 0.3 * Math.sin(ts * 0.0015 + p.phase)) : 1;
        const a = p.alpha * tw;
        if (p.hue) {
          ctx.fillStyle = `oklch(0.84 0.1 ${getComputedStyle(document.documentElement).getPropertyValue('--accent-h') || 190} / ${a})`;
        } else {
          ctx.fillStyle = `rgba(237, 235, 228, ${a})`;
        }
        ctx.beginPath();
        ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2);
        ctx.fill();
      }

      // connection lines near cursor — micro web
      const near = particles.filter((p) => {
        const dx = p.x - m.x, dy = p.y - m.y;
        return dx * dx + dy * dy < 26000;
      });
      ctx.strokeStyle = `oklch(0.84 0.1 ${getComputedStyle(document.documentElement).getPropertyValue('--accent-h') || 190} / 0.14)`;
      ctx.lineWidth = 0.5;
      for (let i = 0; i < near.length; i++) {
        for (let j = i + 1; j < near.length; j++) {
          const a = near[i], b = near[j];
          const dx = a.x - b.x, dy = a.y - b.y;
          const d2 = dx * dx + dy * dy;
          if (d2 < 6400) {
            ctx.globalAlpha = 1 - d2 / 6400;
            ctx.beginPath();
            ctx.moveTo(a.x, a.y);
            ctx.lineTo(b.x, b.y);
            ctx.stroke();
          }
        }
      }
      ctx.globalAlpha = 1;

      raf = requestAnimationFrame(draw);
    };

    resize();
    draw(0);
    window.addEventListener('resize', resize);
    return () => {
      cancelAnimationFrame(raf);
      window.removeEventListener('resize', resize);
    };
  }, [motion, intensity]);

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

window.Field = Field;
