/* ============================================================
   Agent Swarm — animated canvas for the hero
   Renders nodes drifting, connecting, then converging on a
   probability output that increments toward 67%.
   ============================================================ */
const Swarm = () => {
  const canvasRef = React.useRef(null);
  const [prob, setProb] = React.useState(0);
  const [round, setRound] = React.useState(1);
  const targetProb = 67;

  React.useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const ctx = canvas.getContext('2d');

    const dpr = window.devicePixelRatio || 1;
    const resize = () => {
      const r = canvas.getBoundingClientRect();
      canvas.width = r.width * dpr;
      canvas.height = r.height * dpr;
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
    };
    resize();
    const ro = new ResizeObserver(resize);
    ro.observe(canvas);

    const N = 22;
    const rect = () => canvas.getBoundingClientRect();
    const w0 = rect().width, h0 = rect().height;
    const cx0 = w0/2, cy0 = h0/2;

    // Generate stable agent archetypes (label + color)
    const archetypes = [
      'TRADER', 'ANALYST', 'POLICY', 'INSIDER', 'SKEPTIC',
      'HAWK', 'DOVE', 'WHALE', 'RETAIL', 'QUANT'
    ];

    const nodes = Array.from({length: N}, (_, i) => {
      const ang = (i / N) * Math.PI * 2;
      const r = 40 + Math.random() * 80;
      return {
        x: cx0 + Math.cos(ang) * r,
        y: cy0 + Math.sin(ang) * r,
        vx: (Math.random() - 0.5) * 0.4,
        vy: (Math.random() - 0.5) * 0.4,
        baseAng: ang,
        size: 2 + Math.random() * 2.5,
        label: archetypes[i % archetypes.length],
        weight: 0.4 + Math.random() * 0.6,
        phase: Math.random() * Math.PI * 2,
        // each node has its own probability that wobbles toward target
        myProb: 30 + Math.random() * 50,
      };
    });

    let t0 = performance.now();
    let raf;
    const messages = []; // active "message" pulses traveling between nodes

    const step = (now) => {
      const t = (now - t0) / 1000;
      const r = canvas.getBoundingClientRect();
      const W = r.width, H = r.height;
      const cx = W/2, cy = H/2;

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

      // Subtle grid
      ctx.save();
      ctx.strokeStyle = 'rgba(255,255,255,0.03)';
      ctx.lineWidth = 1;
      const gs = 40;
      for (let x = 0; x < W; x += gs) {
        ctx.beginPath(); ctx.moveTo(x, 0); ctx.lineTo(x, H); ctx.stroke();
      }
      for (let y = 0; y < H; y += gs) {
        ctx.beginPath(); ctx.moveTo(0, y); ctx.lineTo(W, y); ctx.stroke();
      }
      ctx.restore();

      // Center radial pulse
      const pulse = 0.5 + 0.5 * Math.sin(t * 1.2);
      const grad = ctx.createRadialGradient(cx, cy, 0, cx, cy, Math.min(W,H)*0.5);
      grad.addColorStop(0, `rgba(174, 240, 110, ${0.10 + pulse*0.04})`);
      grad.addColorStop(0.5, 'rgba(174, 240, 110, 0.02)');
      grad.addColorStop(1, 'transparent');
      ctx.fillStyle = grad;
      ctx.fillRect(0, 0, W, H);

      // Update nodes — orbital drift around center with noise
      nodes.forEach((n, i) => {
        const orbitR = 100 + 80 * Math.sin(t * 0.3 + n.phase);
        const orbitA = n.baseAng + t * 0.08 + Math.sin(t * 0.5 + n.phase) * 0.4;
        const targetX = cx + Math.cos(orbitA) * orbitR;
        const targetY = cy + Math.sin(orbitA) * orbitR;
        n.x += (targetX - n.x) * 0.04;
        n.y += (targetY - n.y) * 0.04;
        // probabilities slowly converge to target
        n.myProb += (targetProb - n.myProb) * 0.005 + (Math.random() - 0.5) * 0.4;
      });

      // Connections — draw lines between nearby nodes
      ctx.lineWidth = 1;
      for (let i = 0; i < nodes.length; i++) {
        for (let j = i+1; j < nodes.length; j++) {
          const a = nodes[i], b = nodes[j];
          const dx = a.x - b.x, dy = a.y - b.y;
          const d = Math.sqrt(dx*dx + dy*dy);
          if (d < 130) {
            const alpha = (1 - d/130) * 0.35;
            ctx.strokeStyle = `rgba(174, 240, 110, ${alpha * 0.5})`;
            ctx.beginPath(); ctx.moveTo(a.x, a.y); ctx.lineTo(b.x, b.y); ctx.stroke();
          }
        }
      }

      // Spawn message pulses occasionally
      if (Math.random() < 0.08 && messages.length < 8) {
        const a = nodes[Math.floor(Math.random()*nodes.length)];
        const b = nodes[Math.floor(Math.random()*nodes.length)];
        if (a !== b) {
          const dx = a.x - b.x, dy = a.y - b.y;
          if (Math.sqrt(dx*dx+dy*dy) < 200) {
            messages.push({ a, b, p: 0 });
          }
        }
      }

      // Animate messages
      for (let i = messages.length - 1; i >= 0; i--) {
        const m = messages[i];
        m.p += 0.025;
        if (m.p >= 1) { messages.splice(i, 1); continue; }
        const x = m.a.x + (m.b.x - m.a.x) * m.p;
        const y = m.a.y + (m.b.y - m.a.y) * m.p;
        const r = 3.5 * (1 - Math.abs(m.p - 0.5) * 1.4);
        ctx.fillStyle = `rgba(220, 255, 180, ${0.9 * (1 - Math.abs(m.p - 0.5) * 1.4)})`;
        ctx.beginPath(); ctx.arc(x, y, r, 0, Math.PI*2); ctx.fill();
      }

      // Draw nodes
      nodes.forEach((n) => {
        // glow
        const g = ctx.createRadialGradient(n.x, n.y, 0, n.x, n.y, n.size * 5);
        g.addColorStop(0, 'rgba(174, 240, 110, 0.5)');
        g.addColorStop(1, 'transparent');
        ctx.fillStyle = g;
        ctx.beginPath(); ctx.arc(n.x, n.y, n.size * 5, 0, Math.PI*2); ctx.fill();

        // core
        ctx.fillStyle = '#caf590';
        ctx.beginPath(); ctx.arc(n.x, n.y, n.size, 0, Math.PI*2); ctx.fill();

        // tiny label
        ctx.font = '9px ui-monospace, monospace';
        ctx.fillStyle = 'rgba(243,245,244,0.55)';
        ctx.fillText(n.label, n.x + n.size + 4, n.y + 3);
      });

      raf = requestAnimationFrame(step);
    };

    raf = requestAnimationFrame(step);

    // Probability counter — gradually approach target with subtle noise
    let probT = 0;
    const probTimer = setInterval(() => {
      probT += 0.04;
      const eased = 1 - Math.pow(1 - Math.min(probT, 1), 3);
      const noise = probT >= 1 ? (Math.random() - 0.5) * 0.6 : 0;
      setProb(targetProb * eased + noise);
    }, 60);

    // Round counter
    let r = 1;
    const roundTimer = setInterval(() => {
      r = (r % 42) + 1;
      setRound(r);
    }, 220);

    return () => {
      cancelAnimationFrame(raf);
      ro.disconnect();
      clearInterval(probTimer);
      clearInterval(roundTimer);
    };
  }, []);

  return (
    <div className="swarm-wrap">
      <canvas ref={canvasRef} />
      <div className="swarm-overlay">
        <div className="row">
          <span className="tag">SCENARIO · MIDEAST · v1.4</span>
          <span className="tag">SWARM · ACTIVE</span>
        </div>
        <div className="row">
          <span className="tag">ROUND {String(round).padStart(2,'0')}/42</span>
          <span className="tag">BRIER 0.082 · ↑</span>
        </div>
      </div>
      <div className="swarm-output">
        <div className="label">Simulated probability</div>
        <div className="prob">{prob.toFixed(1)}<span>%</span></div>
        <div className="delta">MKT 54.0 &nbsp;·&nbsp; <b>+13.0 div</b></div>
      </div>
    </div>
  );
};

window.Swarm = Swarm;
