// Attribution graph — `aurek trace` chain-of-custody DAG.
// Animated directed graph: a request fans out across agents and tools,
// with edges drawing themselves and packets flowing along.
const { useEffect: useEffectAT, useRef: useRefAT } = React;

function AttributionGraph() {
  const ref = useRefAT(null);
  useEffectAT(() => {
    const canvas = ref.current;
    const ctx = canvas.getContext("2d");
    const dpr = Math.min(window.devicePixelRatio || 1, 2);
    const W = 720, H = 420;
    canvas.width = W * dpr; canvas.height = H * dpr;
    canvas.style.width = "100%";
    canvas.style.maxWidth = W + "px";
    canvas.style.height = H + "px";
    ctx.setTransform(dpr, 0, 0, dpr, 0, 0);

    // Nodes (chain of custody)
    const nodes = [
      { id: "user",     x: 60,  y: 210, label: "user.req",        kind: "user"   },
      { id: "router",   x: 200, y: 210, label: "agent:router",    kind: "agent"  },
      { id: "rag",      x: 360, y: 110, label: "agent:rag",       kind: "agent"  },
      { id: "exec",     x: 360, y: 210, label: "agent:exec",      kind: "agent"  },
      { id: "approver", x: 360, y: 320, label: "agent:approver",  kind: "human"  },
      { id: "vec",      x: 540, y: 80,  label: "tool:vector_q",   kind: "tool"   },
      { id: "doc",      x: 540, y: 150, label: "doc:contract.pdf",kind: "data"   },
      { id: "sql",      x: 540, y: 220, label: "tool:sql_select", kind: "tool"   },
      { id: "deploy",   x: 540, y: 290, label: "tool:deploy",     kind: "tool", risky: true },
      { id: "slack",    x: 540, y: 360, label: "human:sarah",     kind: "human"  },
    ];
    const edges = [
      { a: "user",     b: "router",   ts: "14:22:08.001", verdict: "allow" },
      { a: "router",   b: "rag",      ts: "14:22:08.012", verdict: "allow" },
      { a: "router",   b: "exec",     ts: "14:22:08.015", verdict: "allow" },
      { a: "router",   b: "approver", ts: "14:22:08.018", verdict: "escalate" },
      { a: "rag",      b: "vec",      ts: "14:22:08.024", verdict: "allow" },
      { a: "rag",      b: "doc",      ts: "14:22:08.041", verdict: "allow" },
      { a: "exec",     b: "sql",      ts: "14:22:08.063", verdict: "allow" },
      { a: "exec",     b: "deploy",   ts: "14:22:08.072", verdict: "deny"  },
      { a: "approver", b: "slack",    ts: "14:22:08.090", verdict: "allow" },
    ];
    const nodeMap = Object.fromEntries(nodes.map(n => [n.id, n]));

    // Animation state
    let raf;
    let t0 = performance.now();

    function colorFor(verdict) {
      return verdict === "allow"  ? "oklch(0.80 0.14 145)"
           : verdict === "deny"   ? "oklch(0.70 0.18 25)"
           : "oklch(0.82 0.14 75)";
    }
    function nodeFill(kind, risky) {
      if (risky) return "oklch(0.70 0.18 25 / 0.18)";
      if (kind === "human") return "oklch(0.82 0.14 75 / 0.15)";
      if (kind === "tool")  return "rgba(255,255,255,0.04)";
      if (kind === "data")  return "rgba(255,255,255,0.06)";
      if (kind === "user")  return "rgba(255,255,255,0.08)";
      return "rgba(255,255,255,0.05)";
    }

    function tick(now) {
      const t = (now - t0) / 1000;
      ctx.clearRect(0, 0, W, H);

      // Edges: each edge's reveal is staged 0..1 over time, then loops.
      const cycle = 6.0; // seconds per full loop
      const phase = (t % cycle) / cycle; // 0..1

      edges.forEach((e, i) => {
        const A = nodeMap[e.a], B = nodeMap[e.b];
        const stagger = (i / edges.length) * 0.6; // edges reveal staggered in first 60%
        const reveal = Math.max(0, Math.min(1, (phase - stagger) / 0.25));

        // Static line (faint)
        ctx.strokeStyle = "rgba(255,255,255,0.06)";
        ctx.lineWidth = 1;
        ctx.beginPath();
        ctx.moveTo(A.x, A.y);
        ctx.lineTo(B.x, B.y);
        ctx.stroke();

        // Animated draw line
        const dx = B.x - A.x, dy = B.y - A.y;
        const ex = A.x + dx * reveal, ey = A.y + dy * reveal;
        const c = colorFor(e.verdict);
        ctx.strokeStyle = c.replace(")", " / 0.7)");
        ctx.lineWidth = 1.4;
        ctx.beginPath();
        ctx.moveTo(A.x, A.y);
        ctx.lineTo(ex, ey);
        ctx.stroke();

        // Packet (after edge revealed)
        if (reveal >= 1) {
          const packetT = ((phase - stagger - 0.25) / (1 - stagger - 0.25)) % 1;
          const px = A.x + dx * packetT;
          const py = A.y + dy * packetT;
          ctx.fillStyle = c;
          ctx.beginPath();
          ctx.arc(px, py, 3, 0, Math.PI * 2);
          ctx.fill();
          // halo
          ctx.fillStyle = c.replace(")", " / 0.25)");
          ctx.beginPath();
          ctx.arc(px, py, 7, 0, Math.PI * 2);
          ctx.fill();
        }

        // Arrow at end (small)
        if (reveal > 0.95) {
          const ang = Math.atan2(dy, dx);
          const tipX = B.x - Math.cos(ang) * 28;
          const tipY = B.y - Math.sin(ang) * 28;
          ctx.fillStyle = c.replace(")", " / 0.7)");
          ctx.beginPath();
          ctx.moveTo(tipX, tipY);
          ctx.lineTo(tipX - Math.cos(ang - 0.4) * 6, tipY - Math.sin(ang - 0.4) * 6);
          ctx.lineTo(tipX - Math.cos(ang + 0.4) * 6, tipY - Math.sin(ang + 0.4) * 6);
          ctx.closePath();
          ctx.fill();
        }
      });

      // Nodes
      for (const n of nodes) {
        const w = 130, h = 28;
        const x = n.x - w/2, y = n.y - h/2;
        ctx.fillStyle = nodeFill(n.kind, n.risky);
        ctx.strokeStyle = n.risky ? "oklch(0.70 0.18 25 / 0.6)" : "rgba(255,255,255,0.18)";
        ctx.lineWidth = 1;
        ctx.beginPath();
        ctx.roundRect(x, y, w, h, 4);
        ctx.fill();
        ctx.stroke();

        // dot
        const dotColor = n.kind === "human" ? "var(--amber)" :
                        n.kind === "tool"  ? "rgba(243,240,234,0.7)" :
                        n.kind === "data"  ? "oklch(0.80 0.14 145)" :
                        n.kind === "user"  ? "var(--amber)" :
                        "rgba(243,240,234,0.85)";
        ctx.fillStyle = dotColor === "var(--amber)" ? "oklch(0.82 0.14 75)" : dotColor;
        ctx.beginPath();
        ctx.arc(x + 10, y + h/2, 2.6, 0, Math.PI * 2);
        ctx.fill();

        ctx.font = "500 11px 'JetBrains Mono', monospace";
        ctx.fillStyle = "rgba(243,240,234,0.92)";
        ctx.textBaseline = "middle";
        ctx.fillText(n.label, x + 20, y + h/2 + 1);
      }

      raf = requestAnimationFrame(tick);
    }
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, []);

  return (
    <div style={{ position: "relative" }}>
      <canvas ref={ref} style={{ display: "block" }}/>
      <div className="mono" style={{
        position: "absolute", top: 14, left: 14,
        fontSize: 10, letterSpacing: "0.2em",
        color: "var(--text-faint)", textTransform: "uppercase",
      }}>
        $ aurek trace req_8f3a..c821 --graph
      </div>
      <div className="mono" style={{
        position: "absolute", top: 14, right: 14,
        fontSize: 10, letterSpacing: "0.18em",
        color: "var(--text-faint)",
      }}>
        9 hops · signed · exportable
      </div>
    </div>
  );
}

function AttributionSection() {
  return (
    <section id="trace" style={{ padding: "120px 28px", borderBottom: "1px solid var(--line)", position: "relative" }}>
      <div style={{ maxWidth: 1200, margin: "0 auto" }}>
        <div className="mono" style={{ fontSize: 10, letterSpacing: "0.3em", color: "var(--text-faint)", textTransform: "uppercase", marginBottom: 16 }}>
          ▸ Attribution
        </div>
        <h2 style={{ fontSize: 44, margin: "0 0 16px", letterSpacing: "-0.02em", fontWeight: 600, lineHeight: 1.08 }}>
          When something goes wrong,<br/>
          <span style={{ color: "var(--text-dim)" }}>you'll know whose fault it was.</span>
        </h2>
        <p style={{ fontSize: 16, color: "var(--text-dim)", maxWidth: 720, lineHeight: 1.65, margin: "0 0 50px" }}>
          Every action carries a chain of custody — which agent invoked it,
          on whose behalf, against which policy, with what data. <code style={{ color: "var(--amber)", fontFamily: "JetBrains Mono, monospace" }}>aurek trace</code> renders the
          full directed graph. Hand it to your post-mortem; hand it to your
          regulator. Either way the answer is unambiguous.
        </p>
        <div style={{
          border: "1px solid var(--line)",
          borderRadius: 8,
          padding: "30px 20px 20px",
          background: "linear-gradient(180deg, rgba(14,14,16,0.6), rgba(8,8,10,0.9))",
        }}>
          <AttributionGraph/>
        </div>
        <div style={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 18, marginTop: 24 }}>
          {[
            ["Hops captured", "every"],
            ["Cryptographic signing", "ed25519 per hop"],
            ["Replayable", "yes — deterministic"],
          ].map(([k,v]) => (
            <div key={k} className="mono" style={{ border: "1px solid var(--line)", borderRadius: 6, padding: "14px 16px", display: "flex", justifyContent: "space-between", fontSize: 12 }}>
              <span style={{ color: "var(--text-faint)", letterSpacing: "0.1em" }}>{k}</span>
              <span style={{ color: "var(--amber)" }}>{v}</span>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

Object.assign(window, { AttributionSection, AttributionGraph });
