// hyperspace.jsx — The cinematic hero canvas.
// A living, breathing agent engine visualization. Deals stream through
// concentric rings toward the center (∞ → 0 → 1), signals pulse outward,
// receipts scroll by. Everything renders on canvas for 60fps at any resolution.

const Hyperspace = ({ intensity = 1, mode = "engine" }) => {
  const canvasRef = React.useRef(null);
  const rafRef = React.useRef(null);
  const stateRef = React.useRef(null);

  React.useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const ctx = canvas.getContext("2d");
    const dpr = Math.min(window.devicePixelRatio || 1, 2);

    let W = 0, H = 0, CX = 0, CY = 0;
    const resize = () => {
      const rect = canvas.getBoundingClientRect();
      if (rect.width === 0 || rect.height === 0) return;
      W = rect.width; H = rect.height;
      CX = W / 2; CY = H / 2;
      canvas.width = W * dpr;
      canvas.height = H * dpr;
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
      // Paint initial dark bg so it's not transparent
      ctx.fillStyle = "#07070a";
      ctx.fillRect(0, 0, W, H);
    };
    resize();
    const ro = new ResizeObserver(resize);
    ro.observe(canvas);

    // Stars — deep-field particles traveling toward the viewer
    const STAR_COUNT = 200;
    const stars = Array.from({ length: STAR_COUNT }, () => ({
      a: Math.random() * Math.PI * 2,      // angle
      r: Math.random(),                     // distance (0..1)
      v: 0.0010 + Math.random() * 0.0030,   // velocity outward
      len: 10 + Math.random() * 46,
      bright: 0.4 + Math.random() * 0.5,
    }));

    // Deals — named objects traveling along radial paths to center
    const dealLabels = [
      "MANDATE-7721", "M&A-INFRA-Δ", "LP-CAP-2B", "TGT-ENERGY-RE",
      "PIPE-2041", "BUY-SIDE-FT", "SIG-FINTECH", "ORIG-44",
      "COVENANT-ΛΞ", "RCPT-90817", "AGENT-KERN-3", "DEAL-FLOW-07",
    ];
    const deals = Array.from({ length: 10 }, (_, i) => ({
      a: (i / 10) * Math.PI * 2 + Math.random() * 0.4,
      r: Math.random(),
      v: 0.0006 + Math.random() * 0.0008,
      label: dealLabels[i % dealLabels.length],
      kind: Math.random() > 0.6 ? "gold" : "cream",
    }));

    // Rings — the H.E.L.I.U.S. concentric stages
    const rings = [
      { r: 0.15, label: "SYNTHESIS", phase: 0 },
      { r: 0.28, label: "UNDERWRITE", phase: 0.5 },
      { r: 0.42, label: "INITIATE", phase: 1.0 },
      { r: 0.58, label: "LOCATE", phase: 1.5 },
      { r: 0.74, label: "ENGAGE", phase: 2.0 },
      { r: 0.90, label: "HORIZON", phase: 2.5 },
    ];

    let t0 = performance.now();

    const tick = (now) => {
      const t = (now - t0) / 1000;
      const maxR = Math.hypot(W, H) * 0.55;

      // Trail fade — the cinematic slip-stream effect
      ctx.fillStyle = "rgba(10, 10, 15, 0.12)";
      ctx.fillRect(0, 0, W, H);

      // Radial gold glow at center (the "1" — the output)
      const grad = ctx.createRadialGradient(CX, CY, 0, CX, CY, maxR * 0.35);
      const pulse = 0.6 + Math.sin(t * 0.8) * 0.2;
      grad.addColorStop(0, `rgba(233, 200, 119, ${0.22 * pulse * intensity})`);
      grad.addColorStop(0.4, `rgba(200, 162, 75, ${0.06 * intensity})`);
      grad.addColorStop(1, "rgba(10, 10, 15, 0)");
      ctx.fillStyle = grad;
      ctx.fillRect(0, 0, W, H);

      // Deep starfield — hyperspace streaks
      ctx.lineCap = "round";
      for (const s of stars) {
        s.r += s.v * 1.4;
        if (s.r > 1) { s.r = 0; s.a = Math.random() * Math.PI * 2; }
        const rPx = s.r * maxR;
        const x = CX + Math.cos(s.a) * rPx;
        const y = CY + Math.sin(s.a) * rPx;
        const tx = CX + Math.cos(s.a) * (rPx - s.len * s.r * 1.5);
        const ty = CY + Math.sin(s.a) * (rPx - s.len * s.r * 1.5);
        const alpha = s.bright * (0.25 + s.r * 0.65) * intensity;
        ctx.strokeStyle = `rgba(242, 237, 224, ${Math.min(0.85, alpha)})`;
        ctx.lineWidth = 0.8 + s.r * 1.0;
        ctx.beginPath();
        ctx.moveTo(tx, ty);
        ctx.lineTo(x, y);
        ctx.stroke();
      }

      // Concentric rings — the protocol stages
      const ringScale = Math.min(W, H) * 0.52;
      for (let i = 0; i < rings.length; i++) {
        const ring = rings[i];
        const breath = 1 + Math.sin(t * 0.6 + ring.phase) * 0.008;
        const r = ring.r * ringScale * breath;
        ctx.strokeStyle = `rgba(200, 162, 75, ${0.08 + 0.04 * Math.sin(t * 0.4 + ring.phase)})`;
        ctx.lineWidth = 1;
        ctx.beginPath();
        ctx.arc(CX, CY, r, 0, Math.PI * 2);
        ctx.stroke();

        // orbiting tick marks
        const tickCount = 48;
        for (let k = 0; k < tickCount; k++) {
          const a = (k / tickCount) * Math.PI * 2 + t * 0.04 * (i % 2 === 0 ? 1 : -1) * (1 + i * 0.1);
          const x1 = CX + Math.cos(a) * r;
          const y1 = CY + Math.sin(a) * r;
          const x2 = CX + Math.cos(a) * (r + 2);
          const y2 = CY + Math.sin(a) * (r + 2);
          const alpha = 0.04 + 0.18 * Math.pow(Math.sin((k / tickCount) * Math.PI * 4 + t), 8);
          ctx.strokeStyle = `rgba(233, 200, 119, ${alpha})`;
          ctx.lineWidth = 1;
          ctx.beginPath();
          ctx.moveTo(x1, y1);
          ctx.lineTo(x2, y2);
          ctx.stroke();
        }
      }

      // Converging deals — labeled objects flowing toward center
      ctx.font = '10px "JetBrains Mono", monospace';
      for (const d of deals) {
        d.r -= d.v;
        if (d.r < 0.02) {
          d.r = 1;
          d.a = Math.random() * Math.PI * 2;
          d.label = dealLabels[Math.floor(Math.random() * dealLabels.length)];
          d.kind = Math.random() > 0.55 ? "gold" : "cream";
        }
        const rPx = d.r * ringScale * 0.95;
        const x = CX + Math.cos(d.a) * rPx;
        const y = CY + Math.sin(d.a) * rPx;
        const col = d.kind === "gold" ? "233, 200, 119" : "242, 237, 224";
        const trailAlpha = 0.5 * (1 - d.r) + 0.2;

        // trail
        ctx.strokeStyle = `rgba(${col}, ${0.4 * trailAlpha})`;
        ctx.lineWidth = 1;
        ctx.beginPath();
        const tx = CX + Math.cos(d.a) * (rPx + 18);
        const ty = CY + Math.sin(d.a) * (rPx + 18);
        ctx.moveTo(tx, ty);
        ctx.lineTo(x, y);
        ctx.stroke();

        // node
        ctx.fillStyle = `rgba(${col}, ${0.9})`;
        ctx.beginPath();
        ctx.arc(x, y, 2, 0, Math.PI * 2);
        ctx.fill();

        // label
        if (d.r < 0.7 && d.r > 0.1) {
          ctx.fillStyle = `rgba(${col}, ${0.55})`;
          ctx.fillText(d.label, x + 6, y - 6);
        }
      }

      // Central "1" — the output node
      const core = 4 + Math.sin(t * 1.4) * 1.5;
      ctx.fillStyle = "rgba(233, 200, 119, 0.95)";
      ctx.beginPath();
      ctx.arc(CX, CY, core, 0, Math.PI * 2);
      ctx.fill();
      // corona
      const cgrad = ctx.createRadialGradient(CX, CY, 0, CX, CY, 40);
      cgrad.addColorStop(0, "rgba(233, 200, 119, 0.4)");
      cgrad.addColorStop(1, "rgba(233, 200, 119, 0)");
      ctx.fillStyle = cgrad;
      ctx.beginPath();
      ctx.arc(CX, CY, 40, 0, Math.PI * 2);
      ctx.fill();

      rafRef.current = requestAnimationFrame(tick);
    };
    // Paint one frame synchronously so content is visible even if RAF is suspended
    tick(performance.now());
    rafRef.current = requestAnimationFrame(tick);

    return () => {
      cancelAnimationFrame(rafRef.current);
      ro.disconnect();
    };
  }, [intensity, mode]);

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

window.Hyperspace = Hyperspace;
