// architecture-section.jsx — radial mindmap: agent-runtime at the core.

const ArchitectureSection = () => {
  const ref = React.useRef(null);
  const inView = useInView(ref, { threshold: 0.15, once: true });
  const [t, setT] = React.useState(0);
  useRaf((s) => setT(s), inView);

  // Canvas 1000 x 780, core at (500, 400)
  const CX = 500, CY = 400;

  // Nodes: each with polar position (angle in deg, radius) for layout clarity,
  // then converted to x/y. Angle 0 = right, 90 = down.
  // Three rings:
  //  r=0     -> agent-runtime (core)
  //  r=200   -> internal cluster pods it talks to
  //  r=340   -> data substrate + LLM apis + external agents
  const polar = (deg, r) => {
    const rad = (deg - 90) * Math.PI / 180; // 0 deg = top
    return { x: CX + Math.cos(rad) * r, y: CY + Math.sin(rad) * r };
  };

  const nodes = [
    // CORE · Agno Agents hub (replaces the box)
    { id: 'agent', kind: 'coreHub', label: 'Agno',
      sub: 'AGENTS',
      ...polar(0, 0), group: 'core', isCoreHub: true },

    // INNER RING · cluster pods (angles chosen so links don't cross)
    { id: 'web',      kind: 'pod',  label: 'web',
      sub: 'Next.js 16 · Payload',
      tags: ['HPA 1-5', ':3000'],
      ...polar(320, 240), w: 200, h: 90, group: 'app' },

    { id: 'mcp',      kind: 'pod',  label: 'mcp',
      sub: 'Bun · Typesense proxy',
      tags: [':3001'],
      ...polar(40, 240), w: 200, h: 82, group: 'app' },

    { id: 'keycloak', kind: 'pod',  label: 'keycloak',
      sub: 'OIDC · realm-job',
      tags: [':8080'],
      ...polar(180, 200), w: 200, h: 82, group: 'app' },

    // OUTER RING · state / data (minio adjacent to postgres)
    { id: 'postgres',  kind: 'db', label: 'postgres',
      sub: 'cloudnativepg',
      tags: ['payload', 'agno'],
      ...polar(265, 400), w: 180, h: 82, group: 'data' },

    { id: 'minio',     kind: 'db', label: 'minio',
      sub: 'StatefulSet · S3',
      tags: [':9000'],
      ...polar(245, 390), w: 170, h: 74, group: 'data' },

    { id: 'typesense', kind: 'db', label: 'typesense',
      sub: 'hybrid search + RAG',
      tags: [':8108'],
      ...polar(80, 380), w: 200, h: 82, group: 'data' },

    // OUTER RING · external LLM providers
    { id: 'anthropic', kind: 'ext', label: 'Anthropic',
      sub: 'chat models',
      ...polar(135, 360), w: 150, h: 60, group: 'ext' },

    { id: 'openai',    kind: 'ext', label: 'OpenAI',
      sub: 'embeddings',
      ...polar(110, 380), w: 150, h: 60, group: 'ext' },

    // OUTER · external MCP clients (hub)
    { id: 'agents-hub', kind: 'hub', label: 'EXTERNAL',
      sub: 'CLAUDE CODE · CHATGPT',
      ...polar(50, 430), group: 'agents', isHub: true },
  ];

  const find = (id) => nodes.find(n => n.id === id);

  // Offset node bbox so x,y is the visual center
  nodes.forEach(n => {
    if (n.isHub || n.isCoreHub) {
      n._cx = n.x; n._cy = n.y;
    } else {
      n._cx = n.x;
      n._cy = n.y;
      n._left = n.x - n.w / 2;
      n._top  = n.y - n.h / 2;
    }
  });

  // Edges — ONLY real functional connections. No redundant postgres lines.
  const edges = [
    // Core (Agno) → inner cluster
    { from: 'agent', to: 'web',       label: 'PAYLOAD_URL', delay: 0.3 },
    { from: 'agent', to: 'mcp',       label: 'MCP_URL',     delay: 0.5, accent: true },

    // Core → its own state
    { from: 'agent', to: 'postgres',  label: 'schema=agno', delay: 0.7, accent: true },

    // Core → external LLMs
    { from: 'agent', to: 'anthropic', label: 'chat',        delay: 0.9, dashed: true },

    // Keycloak provides sessions to web, mcp and agent-runtime
    { from: 'keycloak', to: 'web',   label: 'session',  delay: 1.0, dashed: true },
    { from: 'keycloak', to: 'mcp',   label: 'session',  delay: 1.1, dashed: true },
    { from: 'keycloak', to: 'agent', label: 'session',  delay: 1.2, dashed: true },

    // App-level essentials (one line each)
    { from: 'web',       to: 'postgres',  label: 'payload',     delay: 1.35 },
    { from: 'web',       to: 'minio',     label: 'uploads',     delay: 1.45, dashed: true },
    { from: 'mcp',       to: 'typesense', label: 'query',       delay: 1.55 },
    { from: 'typesense', to: 'openai',    label: 'embed',       delay: 1.7,  dashed: true },

    // External agents → mcp
    { from: 'agents-hub', to: 'mcp',  label: 'stdio / sse', delay: 1.85, reverse: true },
  ];

  const revealT = Math.min(t, 4.0);

  // Compute edge geometry: from node center to node center, but stop at the node border.
  const edgePath = (a, b) => {
    // From center of a toward center of b, clipped to node rect or circle borders.
    const clipToRect = (node, tx, ty) => {
      if (node.isHub) {
        const dx = tx - node._cx, dy = ty - node._cy;
        const len = Math.hypot(dx, dy) || 1;
        return { x: node._cx + (dx / len) * 36, y: node._cy + (dy / len) * 36 };
      }
      if (node.isCoreHub) {
        const dx = tx - node._cx, dy = ty - node._cy;
        const len = Math.hypot(dx, dy) || 1;
        return { x: node._cx + (dx / len) * 62, y: node._cy + (dy / len) * 62 };
      }
      const hw = node.w / 2, hh = node.h / 2;
      const dx = tx - node._cx, dy = ty - node._cy;
      if (dx === 0 && dy === 0) return { x: node._cx, y: node._cy };
      const tx1 = Math.abs(dx) > 0 ? hw / Math.abs(dx) : Infinity;
      const ty1 = Math.abs(dy) > 0 ? hh / Math.abs(dy) : Infinity;
      const tt = Math.min(tx1, ty1);
      return { x: node._cx + dx * tt, y: node._cy + dy * tt };
    };
    const p1 = clipToRect(a, b._cx, b._cy);
    const p2 = clipToRect(b, a._cx, a._cy);
    const mx = (p1.x + p2.x) / 2;
    const my = (p1.y + p2.y) / 2;
    return { d: `M ${p1.x} ${p1.y} L ${p2.x} ${p2.y}`, p1, p2, mx, my };
  };

  return (
    <section
      id="architecture"
      ref={ref}
      data-screen-label="04 Architecture"
      style={{
        position: 'relative',
        padding: 'clamp(96px, 12vw, 160px) clamp(24px, 5vw, 60px)',
        background: '#f9f9f9',
        color: '#0d0d0d',
        overflow: 'hidden',
      }}
    >
      <div style={{ position: 'relative', maxWidth: 1400, margin: '0 auto' }}>
        <Reveal>
          <div style={{
            display: 'inline-flex', alignItems: 'center', gap: 10,
            fontSize: 12, letterSpacing: '0.2em', textTransform: 'uppercase',
            fontWeight: 600, marginBottom: 24,
          }}>
            <span style={{ width: 9, height: 9, background: '#0d0d0d', display: 'inline-block' }} />
            03 · Arquitectura · MINDMAP
          </div>
        </Reveal>
        <Reveal delay={150}>
          <h2 style={{
            fontSize: 'clamp(40px, 6vw, 84px)',
            fontWeight: 600,
            lineHeight: 1.0,
            letterSpacing: '-0.025em',
            margin: 0,
            maxWidth: '18ch',
          }}>
            El runtime al centro.<br/>
            <span style={{ color: 'rgba(13,13,13,0.3)' }}>Agno orquesta,</span><br/>
            el resto sirve.
          </h2>
        </Reveal>
        <Reveal delay={300}>
          <p style={{
            marginTop: 28, fontSize: 'clamp(16px, 1.3vw, 19px)',
            maxWidth: '58ch', lineHeight: 1.55,
            color: 'rgba(13,13,13,0.7)',
          }}>
            <code style={{ background: '#a1f75e', padding: '0 6px' }}>Agno Agents</code> orquesta el sistema:
            llama a <code>web</code> para Payload, a <code>mcp</code> para búsqueda, y persiste en el schema <code>agno</code>.
            <code>keycloak</code> provee sesión a los tres. Cada línea es una conexión real.
          </p>
        </Reveal>

        <div style={{ marginTop: 72 }}>
          <div style={{
            position: 'relative',
            background: '#fff',
            border: '1px solid rgba(13,13,13,0.12)',
            overflow: 'hidden',
          }}>
            <div style={{
              display: 'flex', alignItems: 'center', justifyContent: 'space-between',
              padding: '14px 20px',
              borderBottom: '1px solid rgba(13,13,13,0.12)',
              fontFamily: "'JetBrains Mono', ui-monospace, monospace",
              fontSize: 11, letterSpacing: '0.1em', textTransform: 'uppercase',
              color: 'rgba(13,13,13,0.6)',
            }}>
              <span><span style={{ color: '#0d0d0d' }}>▪</span> nexus · topology</span>
              <span style={{ display: 'flex', gap: 20 }}>
                <span><span style={{ color: '#a1f75e' }}>●</span> runtime-centric</span>
                <span>12 nodes · 12 edges</span>
              </span>
            </div>

            <div style={{ padding: 'clamp(12px, 2vw, 32px)' }}>
              <svg viewBox="0 0 1000 780" style={{ width: '100%', height: 'auto', display: 'block' }}>
                <defs>
                  <filter id="arch-glow">
                    <feGaussianBlur stdDeviation="3" result="blur"/>
                    <feMerge>
                      <feMergeNode in="blur"/>
                      <feMergeNode in="SourceGraphic"/>
                    </feMerge>
                  </filter>
                  <radialGradient id="core-halo" cx="0.5" cy="0.5" r="0.5">
                    <stop offset="0%" stopColor="#a1f75e" stopOpacity="0.22"/>
                    <stop offset="70%" stopColor="#a1f75e" stopOpacity="0.04"/>
                    <stop offset="100%" stopColor="#a1f75e" stopOpacity="0"/>
                  </radialGradient>
                </defs>

                {/* Concentric guide rings (very subtle) */}
                {[200, 340, 430].map((r, i) => (
                  <circle key={i} cx={CX} cy={CY} r={r}
                    fill="none" stroke="rgba(13,13,13,0.05)" strokeWidth="1"
                    strokeDasharray="2 6"/>
                ))}

                {/* Namespace label */}
                <text x={CX} y={38} textAnchor="middle"
                  fontFamily="'JetBrains Mono', ui-monospace, monospace"
                  fontSize="10" letterSpacing="0.22em"
                  fill="rgba(13,13,13,0.35)">
                  NAMESPACE · NEXUS
                </text>

                {/* Core halo */}
                <circle cx={CX} cy={CY} r="170" fill="url(#core-halo)"/>

                {/* Edges */}
                {edges.map((e, i) => {
                  const srcId = e.reverse ? e.to : e.from;
                  const dstId = e.reverse ? e.from : e.to;
                  const src = find(srcId), dst = find(dstId);
                  if (!src || !dst) return null;
                  const { d, p1, p2, mx, my } = edgePath(src, dst);
                  const len = Math.hypot(p2.x - p1.x, p2.y - p1.y);
                  const appearT = Math.max(0, Math.min(1, (revealT - e.delay) / 0.55));
                  const phase = ((t * 0.32 + i * 0.17) % 1);
                  const solidColor = e.accent ? '#0d0d0d' : 'rgba(13,13,13,0.45)';

                  // Place label at 38% of the line from the source (near core side),
                  // then push it perpendicular so it doesn't sit on top of the edge.
                  const t38 = 0.38;
                  const baseX = p1.x + (p2.x - p1.x) * t38;
                  const baseY = p1.y + (p2.y - p1.y) * t38;
                  const vx = p2.x - p1.x, vy = p2.y - p1.y;
                  const vlen = Math.hypot(vx, vy) || 1;
                  // Perpendicular, chosen to push away from canvas center
                  let nx = -vy / vlen, ny = vx / vlen;
                  if ((baseX - CX) * nx + (baseY - CY) * ny < 0) { nx = -nx; ny = -ny; }
                  const labX = baseX + nx * 10;
                  const labY = baseY + ny * 10;

                  return (
                    <g key={i}>
                      <path
                        d={d}
                        fill="none"
                        stroke={e.dashed ? 'rgba(13,13,13,0.25)' : solidColor}
                        strokeWidth={e.accent ? 1.4 : 1}
                        strokeDasharray={e.dashed ? '3 4' : len}
                        strokeDashoffset={e.dashed ? 0 : len * (1 - appearT)}
                        opacity={e.dashed ? appearT * 0.95 : 1}
                        strokeLinecap="round"
                      />
                      {appearT > 0.9 && !e.dashed && (
                        <PacketOnPath d={d} phase={phase} accent={e.accent}/>
                      )}
                      {e.label && appearT > 0.95 && (
                        <g transform={`translate(${labX}, ${labY})`}>
                          <rect
                            x={-(e.label.length * 3.3 + 6)} y={-7}
                            width={e.label.length * 6.6 + 12} height="14"
                            fill="#fff" stroke="rgba(13,13,13,0.12)" strokeWidth="0.8"
                          />
                          <text x={0} y={3} textAnchor="middle"
                            fontFamily="'JetBrains Mono', ui-monospace, monospace"
                            fontSize="9" letterSpacing="0.06em"
                            fill="rgba(13,13,13,0.72)">
                            {e.label}
                          </text>
                        </g>
                      )}
                    </g>
                  );
                })}

                {/* Nodes */}
                {nodes.map((n) => {
                  const groupDelay = ({ core: 0, app: 0.35, data: 0.9, ext: 1.1, agents: 1.5 })[n.group];
                  const appear = Math.max(0, Math.min(1, (revealT - groupDelay) / 0.4));

                  if (n.isCoreHub) {
                    const pulse = 1 + Math.sin(t * 1.6) * 0.06;
                    return (
                      <g key={n.id} opacity={appear}>
                        <circle cx={n._cx} cy={n._cy} r={95 * pulse} fill="none"
                                stroke="#a1f75e" strokeWidth="1" opacity={0.3}/>
                        <circle cx={n._cx} cy={n._cy} r={78 * pulse} fill="none"
                                stroke="#a1f75e" strokeWidth="1" opacity={0.55}/>
                        <circle cx={n._cx} cy={n._cy} r="62" fill="#a1f75e"/>
                        <circle cx={n._cx} cy={n._cy} r="62" fill="none" stroke="#0d0d0d" strokeWidth="1.5"/>
                        <text x={n._cx} y={n._cy - 4} textAnchor="middle"
                              fontFamily="'Public Sans', sans-serif"
                              fontWeight="700" fontSize="22"
                              fill="#0d0d0d"
                              letterSpacing="0.01em">
                          Agno
                        </text>
                        <text x={n._cx} y={n._cy + 16} textAnchor="middle"
                              fontFamily="'JetBrains Mono', ui-monospace, monospace"
                              fontSize="10" letterSpacing="0.22em"
                              fill="rgba(13,13,13,0.72)">
                          AGENTS
                        </text>
                        <text x={n._cx} y={n._cy + 82} textAnchor="middle"
                              fontFamily="'JetBrains Mono', ui-monospace, monospace"
                              fontSize="9" letterSpacing="0.14em"
                              fill="rgba(13,13,13,0.55)">
                          FASTAPI · SCHEMA=AGNO
                        </text>
                      </g>
                    );
                  }

                  if (n.isHub) {
                    const pulse = 1 + Math.sin(t * 2) * 0.08;
                    return (
                      <g key={n.id} opacity={appear}>
                        <circle cx={n._cx} cy={n._cy} r={52 * pulse} fill="none"
                                stroke="#0d0d0d" strokeWidth="1" opacity={0.3}/>
                        <circle cx={n._cx} cy={n._cy} r={40 * pulse} fill="none"
                                stroke="#0d0d0d" strokeWidth="1" opacity={0.55}/>
                        <circle cx={n._cx} cy={n._cy} r="36" fill="#fff"/>
                        <circle cx={n._cx} cy={n._cy} r="36" fill="none" stroke="#0d0d0d" strokeWidth="1.5"/>
                        <text x={n._cx} y={n._cy + 4} textAnchor="middle"
                              fontFamily="'Public Sans', sans-serif"
                              fontWeight="700" fontSize="10"
                              fill="#0d0d0d"
                              letterSpacing="0.12em">
                          EXTERNAL
                        </text>
                        <text x={n._cx} y={n._cy + 62} textAnchor="middle"
                              fontFamily="'JetBrains Mono', ui-monospace, monospace"
                              fontSize="9" letterSpacing="0.14em"
                              fill="rgba(13,13,13,0.55)">
                          CLAUDE CODE · CHATGPT
                        </text>
                      </g>
                    );
                  }

                  // Palette per kind
                  let bg, fg, stroke, accent, tagBg, tagFg, kindLabel;
                  if (n.kind === 'db') {
                    bg = '#fff'; fg = '#0d0d0d'; stroke = 'rgba(13,13,13,0.5)';
                    accent = '#0d0d0d'; tagBg = 'rgba(13,13,13,0.06)'; tagFg = 'rgba(13,13,13,0.75)';
                    kindLabel = n.id === 'postgres' ? 'STATEFUL' : n.id === 'minio' ? 'STATEFULSET' : 'SERVICE';
                  } else if (n.kind === 'ext') {
                    bg = 'rgba(13,13,13,0.04)'; fg = '#0d0d0d'; stroke = 'rgba(13,13,13,0.2)';
                    accent = 'rgba(13,13,13,0.3)'; tagBg = 'transparent'; tagFg = 'rgba(13,13,13,0.5)';
                    kindLabel = 'EXTERNAL';
                  } else {
                    bg = '#0d0d0d'; fg = '#f9f9f9'; stroke = '#0d0d0d';
                    accent = '#a1f75e'; tagBg = 'rgba(161,247,94,0.12)'; tagFg = '#a1f75e';
                    kindLabel = 'POD';
                  }

                  return (
                    <g key={n.id}
                      opacity={appear}
                      transform={`translate(${n._left}, ${n._top + (1 - appear) * 8})`}
                    >
                      <rect width={n.w} height={n.h} fill={bg} stroke={stroke} strokeWidth="1"/>
                      <rect x={0} y={0} width="3" height={n.h} fill={accent}/>

                      {/* kind badge */}
                      <text x={n.w - 10} y={15} textAnchor="end"
                        fontFamily="'JetBrains Mono', ui-monospace, monospace"
                        fontSize="8" letterSpacing="0.16em"
                        fill={n.kind === 'pod'  ? 'rgba(161,247,94,0.75)' :
                              'rgba(13,13,13,0.4)'}>
                        {kindLabel}
                      </text>

                      <text x={14} y={n.kind === 'ext' ? 26 : 34}
                        fontFamily="'Public Sans', sans-serif"
                        fontWeight="700"
                        fontSize={n.kind === 'ext' ? 14 : 16}
                        fill={fg}
                        letterSpacing="0.01em">
                        {n.label}
                      </text>

                      <text x={14} y={n.kind === 'ext' ? 44 : 52}
                        fontFamily="'JetBrains Mono', ui-monospace, monospace"
                        fontSize="10"
                        fill={n.kind === 'pod' ? 'rgba(255,255,255,0.62)' :
                              'rgba(13,13,13,0.55)'}>
                        {n.sub}
                      </text>

                      {/* tag chips */}
                      {n.tags && n.tags.map((tag, j) => {
                        const chipW = tag.length * 7.2 + 18;
                        const perRow = Math.max(1, Math.floor((n.w - 18) / (chipW + 8)));
                        const col = j % perRow;
                        const row = Math.floor(j / perRow);
                        const xOffset = 14 + col * (chipW + 8);
                        const yOffset = (n.kind === 'ext' ? 44 : 60) + row * 18;
                        return (
                          <g key={tag} transform={`translate(${xOffset}, ${yOffset})`}>
                            <rect width={chipW} height="14" fill={tagBg} stroke="none"/>
                            <text x={chipW / 2} y="10" textAnchor="middle"
                              fontFamily="'JetBrains Mono', ui-monospace, monospace"
                              fontSize="9" letterSpacing="0.06em"
                              fill={tagFg}>
                              {tag}
                            </text>
                          </g>
                        );
                      })}
                    </g>
                  );
                })}
              </svg>
            </div>

            {/* Legend footer */}
            <div style={{
              borderTop: '1px solid rgba(13,13,13,0.12)',
              padding: '14px 20px',
              display: 'flex', flexWrap: 'wrap', gap: 24, rowGap: 10,
              fontFamily: "'JetBrains Mono', ui-monospace, monospace",
              fontSize: 10.5, letterSpacing: '0.1em', textTransform: 'uppercase',
              color: 'rgba(13,13,13,0.62)',
            }}>
              <span style={{ display: 'inline-flex', alignItems: 'center', gap: 8 }}>
                <span style={{ width: 14, height: 10, background: '#a1f75e' }}/> core runtime
              </span>
              <span style={{ display: 'inline-flex', alignItems: 'center', gap: 8 }}>
                <span style={{ width: 14, height: 10, background: '#0d0d0d' }}/> cluster pod
              </span>
              <span style={{ display: 'inline-flex', alignItems: 'center', gap: 8 }}>
                <span style={{ width: 14, height: 10, background: '#fff', border: '1px solid rgba(13,13,13,0.5)' }}/> state
              </span>
              <span style={{ display: 'inline-flex', alignItems: 'center', gap: 8 }}>
                <span style={{ width: 14, border: '1px dashed rgba(13,13,13,0.4)' }}/> optional / async
              </span>
              <span style={{ marginLeft: 'auto' }}>helm/nexus-template · argocd</span>
            </div>
          </div>
        </div>

        {/* Pillars */}
        <div style={{
          marginTop: 72,
          display: 'grid',
          gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))',
          gap: 32,
        }}>
          {[
            { label: 'AGNO AGENTS',    text: 'El runtime en el centro. Habla con mcp, web y persiste en el schema agno. Llama a Anthropic para chat.', hl: true },
            { label: 'WEB',            text: 'Next.js 16 + Payload CMS. Fuente de verdad editorial y metadatos del producto.' },
            { label: 'MCP',            text: 'Wrapper Bun sobre Typesense. Expone tools de búsqueda híbrida + RAG a agentes externos.' },
            { label: 'KEYCLOAK',       text: 'OIDC centralizado. Provee sesión a web, mcp y al runtime de agentes. Realm-job de bootstrap.' },
          ].map((p, i) => (
            <Reveal key={p.label} delay={i * 80}>
              <div>
                <div style={{
                  fontSize: 11, letterSpacing: '0.2em', textTransform: 'uppercase',
                  fontWeight: 600, marginBottom: 12,
                  display: 'inline-flex', alignItems: 'center', gap: 8,
                }}>
                  <span style={{
                    width: 9, height: 9,
                    background: p.hl ? '#a1f75e' : '#0d0d0d',
                  }} />
                  {p.label}
                </div>
                <p style={{
                  fontSize: 15, lineHeight: 1.55,
                  color: 'rgba(13,13,13,0.72)', margin: 0,
                  maxWidth: '32ch',
                }}>
                  {p.text}
                </p>
              </div>
            </Reveal>
          ))}
        </div>
      </div>
    </section>
  );
};

// Packet moving along an SVG path
const PacketOnPath = ({ d, phase, accent }) => {
  const pathRef = React.useRef(null);
  const [pt, setPt] = React.useState({ x: 0, y: 0 });
  React.useEffect(() => {
    if (!pathRef.current) return;
    const path = pathRef.current;
    const len = path.getTotalLength();
    const p = path.getPointAtLength(phase * len);
    setPt({ x: p.x, y: p.y });
  }, [phase, d]);
  return (
    <g>
      <path ref={pathRef} d={d} fill="none" stroke="none" />
      <circle cx={pt.x} cy={pt.y} r={accent ? 5 : 4} fill="#a1f75e" filter="url(#arch-glow)" opacity="0.95"/>
      <circle cx={pt.x} cy={pt.y} r="1.8" fill="#0d0d0d"/>
    </g>
  );
};

Object.assign(window, { ArchitectureSection });
