// "Inside the AI": how the agents actually work, with graphics.
const { useEffect: useEffectAi, useState: useStateAi, useRef: useRefAi } = React;

// ---------- Orchestrator graph (interactive) ----------
const AGENT_NODES = [
  { id: 'orch', label: 'Orchestrator', x: 70, y: 175, kind: 'orch' },
  { id: 'recon',  label: 'recon',   x: 270, y: 50,  kind: 'agent', findings: 7,  sev: 'low'  },
  { id: 'auth',   label: 'auth',    x: 270, y: 100, kind: 'agent', findings: 3,  sev: 'high' },
  { id: 'inj',    label: 'inj',     x: 270, y: 150, kind: 'agent', findings: 5,  sev: 'crit' },
  { id: 'bac',    label: 'bac',     x: 270, y: 200, kind: 'agent', findings: 2,  sev: 'high' },
  { id: 'ssrf',   label: 'ssrf',    x: 270, y: 250, kind: 'agent', findings: 1,  sev: 'high' },
  { id: 'cloud',  label: 'cloud',   x: 270, y: 300, kind: 'agent', findings: 4,  sev: 'med'  },
  { id: 'tgt1', label: 'api.acme.com',  x: 520, y: 80,  kind: 'target' },
  { id: 'tgt2', label: 'auth.acme.com', x: 520, y: 145, kind: 'target' },
  { id: 'tgt3', label: 'aws / iam',     x: 520, y: 210, kind: 'target' },
  { id: 'tgt4', label: 'mobile-ios',    x: 520, y: 275, kind: 'target' },
];

const LINKS = [
  ['orch','recon'], ['orch','auth'], ['orch','inj'], ['orch','bac'], ['orch','ssrf'], ['orch','cloud'],
  ['recon','tgt1'], ['recon','tgt2'], ['auth','tgt2'], ['inj','tgt1'], ['bac','tgt1'],
  ['ssrf','tgt1'], ['ssrf','tgt3'], ['cloud','tgt3'], ['recon','tgt4'],
];

const SEV_COLOR = { crit: 'var(--danger)', high: 'var(--warn)', med: 'var(--accent-2)', low: 'var(--text-2)' };

function AgentGraph() {
  const [tick, setTick] = useStateAi(0);
  const [active, setActive] = useStateAi(null); // hovered/selected agent id
  const [pinned, setPinned] = useStateAi(null);

  useEffectAi(() => {
    const id = setInterval(() => setTick(t => (t + 1) % 100000), 33);
    return () => clearInterval(id);
  }, []);

  const nodeMap = Object.fromEntries(AGENT_NODES.map(n => [n.id, n]));
  const focus = pinned || active;

  // which nodes/links are highlighted given focus
  function linkActive(a, b) {
    if (!focus) return null; // null = default state
    if (focus === a || focus === b) return true;
    // orchestrator->focusAgent also counts
    if (a === 'orch' && b === focus) return true;
    return false;
  }
  function nodeDimmed(id) {
    if (!focus) return false;
    if (id === focus || id === 'orch') return false;
    // targets connected to focus stay lit
    const connected = LINKS.some(([a,b]) => (a === focus && b === id) || (b === focus && a === id));
    return !connected;
  }

  const agents = AGENT_NODES.filter(n => n.kind === 'agent');
  const totalFindings = agents.reduce((s, a) => s + a.findings, 0);
  const focusNode = focus ? nodeMap[focus] : null;

  return (
    <div className="ai-graph">
      <svg viewBox="0 0 700 360" preserveAspectRatio="xMidYMid meet" style={{ width: '100%', height: '100%' }}>
        <defs>
          <radialGradient id="agOrchGlow">
            <stop offset="0" stopColor="var(--accent)" stopOpacity="0.7"/>
            <stop offset="1" stopColor="var(--accent)" stopOpacity="0"/>
          </radialGradient>
          <radialGradient id="agTgtGlow">
            <stop offset="0" stopColor="var(--accent-2)" stopOpacity="0.5"/>
            <stop offset="1" stopColor="var(--accent-2)" stopOpacity="0"/>
          </radialGradient>
          <linearGradient id="agLink" x1="0" x2="1">
            <stop offset="0" stopColor="var(--accent)" stopOpacity="0.6" />
            <stop offset="1" stopColor="var(--accent-2)" stopOpacity="0.5" />
          </linearGradient>
        </defs>

        <text x="70"  y="24" fontSize="9" fill="var(--text-3)" fontFamily="JetBrains Mono, monospace" textAnchor="middle" letterSpacing="0.12em">ORCHESTRATOR</text>
        <text x="270" y="24" fontSize="9" fill="var(--text-3)" fontFamily="JetBrains Mono, monospace" textAnchor="middle" letterSpacing="0.12em">AGENT MESH</text>
        <text x="580" y="24" fontSize="9" fill="var(--text-3)" fontFamily="JetBrains Mono, monospace" textAnchor="middle" letterSpacing="0.12em">ATTACK SURFACE</text>

        {/* Links + animated packets */}
        {LINKS.map(([a, b], i) => {
          const A = nodeMap[a], B = nodeMap[b];
          const la = linkActive(a, b);
          const isOn = la === true;
          const isDefault = la === null;
          const baseOpacity = isDefault ? 0.4 : (isOn ? 0.95 : 0.07);
          const sw = isOn ? 1.6 : 0.7;
          // packet position (only on active or default links)
          const speed = isOn ? 1.6 : 1.0;
          const phase = ((tick * speed + i * 37) % 120) / 120;
          const px = A.x + (B.x - A.x) * phase;
          const py = A.y + (B.y - A.y) * phase;
          const showPacket = isDefault || isOn;
          return (
            <g key={i}>
              <line x1={A.x} y1={A.y} x2={B.x} y2={B.y}
                stroke={isOn ? 'url(#agLink)' : 'var(--border-2)'} strokeWidth={sw} opacity={baseOpacity} />
              {showPacket && (
                <circle cx={px} cy={py} r={isOn ? 2.6 : 1.6}
                  fill={isOn ? 'var(--accent-2)' : 'var(--accent-hi)'}
                  opacity={isOn ? 1 : 0.8} />
              )}
            </g>
          );
        })}

        {/* Nodes */}
        {AGENT_NODES.map((n, i) => {
          const dim = nodeDimmed(n.id);
          const isFocus = n.id === focus;
          if (n.kind === 'orch') {
            return (
              <g key={n.id} opacity={dim ? 0.4 : 1}>
                <circle cx={n.x} cy={n.y} r="36" fill="url(#agOrchGlow)" />
                <circle cx={n.x} cy={n.y} r="20" fill="var(--bg-2)" stroke="var(--accent)" strokeWidth="1.4" />
                <circle cx={n.x} cy={n.y} r="3.5" fill="var(--accent)">
                  <animate attributeName="r" values="2.5;5;2.5" dur="2s" repeatCount="indefinite" />
                </circle>
                <text x={n.x} y={n.y + 52} fontSize="10" fill="var(--text)" fontFamily="JetBrains Mono, monospace" textAnchor="middle">orchestrator</text>
                <text x={n.x} y={n.y + 64} fontSize="8" fill="var(--text-3)" fontFamily="JetBrains Mono, monospace" textAnchor="middle">plan · delegate</text>
              </g>
            );
          }
          if (n.kind === 'agent') {
            const col = SEV_COLOR[n.sev];
            return (
              <g key={n.id}
                 style={{ cursor: 'pointer' }}
                 opacity={dim ? 0.32 : 1}
                 onMouseEnter={() => setActive(n.id)}
                 onMouseLeave={() => setActive(null)}
                 onClick={() => setPinned(p => p === n.id ? null : n.id)}>
                <rect x={n.x - 42} y={n.y - 13} width="84" height="26" rx="6"
                  fill={isFocus ? 'var(--surface-2)' : 'var(--bg-2)'}
                  stroke={isFocus ? col : 'var(--accent-line)'} strokeWidth={isFocus ? 1.4 : 0.8} />
                <circle cx={n.x - 31} cy={n.y} r="3" fill={col}>
                  <animate attributeName="opacity" values="0.4;1;0.4" dur={`${1.4 + i*0.12}s`} repeatCount="indefinite" />
                </circle>
                <text x={n.x - 23} y={n.y + 3.5} fontSize="10" fill="var(--text)" fontFamily="JetBrains Mono, monospace">{n.label}</text>
                <text x={n.x + 34} y={n.y + 3.5} fontSize="9" fill={col} fontFamily="JetBrains Mono, monospace" textAnchor="end">{n.findings}</text>
              </g>
            );
          }
          if (n.kind === 'target') {
            return (
              <g key={n.id} opacity={dim ? 0.3 : 1}>
                <circle cx={n.x} cy={n.y} r="22" fill="url(#agTgtGlow)" />
                <rect x={n.x - 15} y={n.y - 10} width="30" height="20" rx="4"
                      fill="var(--bg-2)" stroke="rgba(94,230,255,0.5)" strokeWidth="0.9" />
                <text x={n.x} y={n.y + 3.5} fontSize="8" fill="var(--accent-2)" fontFamily="JetBrains Mono, monospace" textAnchor="middle">tgt</text>
                <text x={n.x + 24} y={n.y + 3.5} fontSize="9" fill="var(--text-2)" fontFamily="JetBrains Mono, monospace">{n.label}</text>
              </g>
            );
          }
        })}
      </svg>

      <div className="ai-graph__hint">
        {focusNode ? (
          <span>
            <strong style={{ color: SEV_COLOR[focusNode.sev] }}>{focusNode.label}</strong> agent · {focusNode.findings} findings · highest severity <strong style={{ color: SEV_COLOR[focusNode.sev] }}>{focusNode.sev}</strong>
            {pinned && <span style={{ color: 'var(--text-3)' }}> · click to release</span>}
          </span>
        ) : (
          <span><strong style={{ color: 'var(--accent-hi)' }}>{totalFindings} findings</strong> across {agents.length} active agents · <span style={{ color: 'var(--text-3)' }}>hover an agent to trace its targets</span></span>
        )}
      </div>
    </div>
  );
}

// ---------- Reasoning stream ----------
const THOUGHT_LINES = [
  { t: 'plan',     text: 'plan: enumerate /v1/users · attempt IDOR via tenant header swap' },
  { t: 'tool',     text: 'tool_call: http.get { url: "/v1/users/me", headers: { Authorization: <T_A> } }' },
  { t: 'observe',  text: 'observe: 200 OK · body contains tenant_id=acme · user_id=42' },
  { t: 'reason',   text: 'reason: id appears to be sequential · try user_id=43 with same token' },
  { t: 'tool',     text: 'tool_call: http.get { url: "/v1/users/43" }' },
  { t: 'observe',  text: 'observe: 200 OK · body contains tenant_id=widgetco · cross-tenant leak' },
  { t: 'conclude', text: 'conclude: BOLA confirmed (CWE-639) · severity=critical · ship CIP-8821' },
  { t: 'handoff',  text: 'handoff → triage agent · attach replay · open Jira SEC-3127' },
];

function ReasoningStream() {
  const [n, setN] = useStateAi(0);
  const wrapRef = useRefAi(null);
  useEffectAi(() => {
    let i = 0;
    const id = setInterval(() => {
      i = (i + 1) % (THOUGHT_LINES.length + 2);
      setN(i);
    }, 1100);
    return () => clearInterval(id);
  }, []);
  useEffectAi(() => {
    if (wrapRef.current) wrapRef.current.scrollTop = wrapRef.current.scrollHeight;
  }, [n]);
  const shown = THOUGHT_LINES.slice(0, n);
  return (
    <div className="reason">
      <div className="reason__head">
        <span className="reason__dot"></span>
        agent · injection · CIP-8821
        <span style={{ marginLeft: 'auto', color: 'var(--text-3)', fontSize: 10 }}>step {Math.min(n, THOUGHT_LINES.length)}/{THOUGHT_LINES.length}</span>
      </div>
      <div className="reason__body" ref={wrapRef}>
        {shown.map((l, i) => (
          <div key={i} className={`reason__line reason__line--${l.t}`}>
            <span className="reason__tag">{l.t}</span>
            <span className="reason__text">{l.text}</span>
          </div>
        ))}
        <span className="term__caret" style={{ marginLeft: 4 }}></span>
      </div>
    </div>
  );
}

// ---------- Exploit chain (animated kill-chain) ----------
function ExploitChain() {
  const [tick, setTick] = useStateAi(0);
  useEffectAi(() => {
    const id = setInterval(() => setTick(t => (t + 1) % 100000), 33);
    return () => clearInterval(id);
  }, []);

  const NODES = {
    env:  { x: 14,  y: 30,  w: 120, h: 46, label: 'leaked .env',     sub: 'github crawl', sev: 'low',  step: 1 },
    key:  { x: 14,  y: 132, w: 120, h: 46, label: 'staging api key', sub: 'reachable',    sev: 'med',  step: 2 },
    auth: { x: 196, y: 50,  w: 124, h: 46, label: 'auth bypass',     sub: 'JWT alg=none', sev: 'high', step: 3 },
    bola: { x: 196, y: 158, w: 124, h: 46, label: 'BOLA',            sub: '/users/{id}',  sev: 'high', step: 3 },
    pwn:  { x: 384, y: 104, w: 112, h: 46, label: 'PWN',             sub: 'tenant data',  sev: 'crit', step: 4 },
  };
  const EDGES = [
    ['env', 'auth'], ['key', 'auth'], ['key', 'bola'],
    ['auth', 'pwn'], ['bola', 'pwn'],
  ];
  const sevColor = (s) => s === 'crit' ? 'var(--danger)' : s === 'high' ? 'var(--warn)' : s === 'med' ? 'var(--accent-2)' : 'var(--text-2)';
  const sevFill  = (s) => s === 'crit' ? 'rgba(255,111,142,0.10)' : s === 'high' ? 'rgba(255,184,111,0.07)' : s === 'med' ? 'rgba(94,230,255,0.06)' : 'rgba(154,163,188,0.05)';

  const cx = (n) => n.x + n.w;          // right edge
  const cy = (n) => n.y + n.h / 2;      // vertical center
  const lx = (n) => n.x;                // left edge

  return (
    <svg viewBox="0 0 510 240" style={{ width: '100%', height: '100%' }}>
      <defs>
        <marker id="chArrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto">
          <path d="M0 1 L9 5 L0 9 z" fill="var(--accent-hi)" />
        </marker>
        <linearGradient id="chEdge" x1="0" x2="1">
          <stop offset="0" stopColor="var(--accent)" stopOpacity="0.7" />
          <stop offset="1" stopColor="var(--accent-2)" stopOpacity="0.7" />
        </linearGradient>
        <filter id="chGlow" x="-40%" y="-40%" width="180%" height="180%">
          <feGaussianBlur stdDeviation="2.4" result="b" />
          <feMerge><feMergeNode in="b"/><feMergeNode in="SourceGraphic"/></feMerge>
        </filter>
      </defs>

      {/* edges with flowing packets */}
      {EDGES.map(([a, b], i) => {
        const A = NODES[a], B = NODES[b];
        const x1 = cx(A), y1 = cy(A), x2 = lx(B), y2 = cy(B);
        const mx = (x1 + x2) / 2;
        const d = `M ${x1} ${y1} C ${mx} ${y1}, ${mx} ${y2}, ${x2} ${y2}`;
        const phase = ((tick * 1.3 + i * 30) % 100) / 100;
        // sample point along the cubic for packet
        const t = phase, mt = 1 - t;
        const px = mt*mt*mt*x1 + 3*mt*mt*t*mx + 3*mt*t*t*mx + t*t*t*x2;
        const py = mt*mt*mt*y1 + 3*mt*mt*t*y1 + 3*mt*t*t*y2 + t*t*t*y2;
        return (
          <g key={i}>
            <path d={d} stroke="url(#chEdge)" strokeWidth="1.5" fill="none" opacity="0.55" markerEnd="url(#chArrow)" />
            <circle cx={px} cy={py} r="2.6" fill="var(--accent-2)" filter="url(#chGlow)" />
          </g>
        );
      })}

      {/* nodes */}
      {Object.values(NODES).map((n, i) => {
        const col = sevColor(n.sev);
        const isCrit = n.sev === 'crit';
        return (
          <g key={i} filter={isCrit ? 'url(#chGlow)' : undefined}>
            <rect x={n.x} y={n.y} width={n.w} height={n.h} rx="9"
                  fill={sevFill(n.sev)} stroke={col} strokeOpacity={isCrit ? 1 : 0.65} strokeWidth={isCrit ? 1.6 : 1} />
            {/* severity tab */}
            <rect x={n.x} y={n.y} width="4" height={n.h} rx="2" fill={col} />
            {/* step badge */}
            <circle cx={n.x + n.w - 13} cy={n.y + 13} r="8" fill="var(--bg)" stroke={col} strokeOpacity="0.5" strokeWidth="0.8" />
            <text x={n.x + n.w - 13} y={n.y + 16} fontSize="8" fill={col} fontFamily="JetBrains Mono, monospace" textAnchor="middle">{n.step}</text>
            <text x={n.x + 14} y={n.y + 22} fontSize="11.5" fill={col} fontFamily="JetBrains Mono, monospace" fontWeight="500">{n.label}</text>
            <text x={n.x + 14} y={n.y + 36} fontSize="8.5" fill="var(--text-3)" fontFamily="JetBrains Mono, monospace">{n.sub}</text>
            {isCrit && (
              <circle cx={n.x + n.w - 13} cy={n.y + 13} r="8" fill="none" stroke={col} strokeWidth="1">
                <animate attributeName="r" values="8;13;8" dur="1.8s" repeatCount="indefinite" />
                <animate attributeName="opacity" values="0.8;0;0.8" dur="1.8s" repeatCount="indefinite" />
              </circle>
            )}
          </g>
        );
      })}

      {/* severity ramp footer */}
      <g>
        <text x="14" y="228" fontSize="8.5" fill="var(--text-3)" fontFamily="JetBrains Mono, monospace" letterSpacing="0.08em">low</text>
        <rect x="42" y="222" width="180" height="4" rx="2" fill="url(#chEdge)" opacity="0.4" />
        <text x="230" y="228" fontSize="8.5" fill="var(--danger)" fontFamily="JetBrains Mono, monospace" letterSpacing="0.08em">critical</text>
        <text x="500" y="228" fontSize="8.5" fill="var(--text-3)" fontFamily="JetBrains Mono, monospace" textAnchor="end" letterSpacing="0.1em">auto-composed</text>
      </g>
    </svg>
  );
}

// ---------- Inside-the-AI section ----------
function InsideAi() {
  return (
    <section className="section" id="ai">
      <div className="container">
        <div className="section-head">
          <div className="section-head__title">
            <span className="eyebrow">05 · Inside the AI</span>
            <h2 style={{ marginTop: 18 }}>It's not a scanner.<br/>It's an attacker that reasons.</h2>
            <p style={{ marginTop: 16, maxWidth: 560 }}>
              Behind every Ciphryn engagement sits a multi-agent system that plans, delegates, and chains primitives the way a senior pentester does. Every step is auditable.
            </p>
          </div>
        </div>

        <div className="ai-grid">
          <div className="ai-card ai-card--wide">
            <div className="ai-card__head">
              <div className="ai-card__num">01 · ORCHESTRATION</div>
              <div className="ai-card__name">An orchestrator delegates to 12 specialized agents.</div>
              <p className="ai-card__desc">Each agent owns a domain (auth, injection, BAC, SSRF, cloud, …). The orchestrator plans the engagement, allocates compute, and synthesizes findings.</p>
            </div>
            <AgentGraph />
          </div>

          <div className="ai-card">
            <div className="ai-card__head">
              <div className="ai-card__num">02 · REASONING</div>
              <div className="ai-card__name">Every action is logged as plan → tool → observe.</div>
              <p className="ai-card__desc">No black boxes. You see exactly why the AI tried something, and what it learned.</p>
            </div>
            <ReasoningStream />
          </div>

          <div className="ai-card">
            <div className="ai-card__head">
              <div className="ai-card__num">03 · CHAINING</div>
              <div className="ai-card__name">Primitives get composed into real exploit paths.</div>
              <p className="ai-card__desc">A leaked key plus a permissive JWT plus a BOLA isn't three medium findings. It's one critical.</p>
            </div>
            <div className="ai-card__viz"><ExploitChain /></div>
          </div>

          <div className="ai-card ai-card--wide ai-card--stripe">
            <div className="ai-card__head">
              <div className="ai-card__num">04 · GUARDRAILS</div>
              <div className="ai-card__name">Sandboxed by default. Audit-grade by design.</div>
              <p className="ai-card__desc">Destructive payloads are quarantined. Out-of-scope hosts are hard-blocked. Every tool call and HTTP request is signed, logged, and replayable for audit.</p>
            </div>
            <div className="guard-grid">
              {[
                { k: 'In-scope only',   v: 'Hard-coded allowlist · IP/SNI/host pinning · zero-trust egress' },
                { k: 'Read-only mode',  v: 'Default. Write operations require explicit per-asset opt-in' },
                { k: 'Replayable PoCs', v: 'Every exploit attempt is recorded as a signed HAR + payload bundle' },
                { k: 'Compute budget',  v: 'Per-engagement token + rate caps · auto-pause on anomaly' },
                { k: 'Human override',  v: 'Senior operator can pause, redirect, or claim any agent in real time' },
                { k: 'Audit log',       v: 'Append-only · SIEM export · SOC 2 / ISO 27001 mapped controls' },
              ].map((g, i) => (
                <div key={i} className="guard">
                  <div className="guard__k">{g.k}</div>
                  <div className="guard__v">{g.v}</div>
                </div>
              ))}
            </div>
          </div>
        </div>
      </div>
    </section>
  );
}

Object.assign(window, { InsideAi });
