/* global React */
const { useState, useEffect, useRef } = React;

function NetworkGraph({ accent = '#C41E1E', ink = '#14120F', sage = '#8B9D5A' }) {
  const ref = useRef(null);
  const [packets, setPackets] = useState([]);

  // Nodes (normalized 0-100)
  const nodes = [
    { id: 'tol', x: 30, y: 58, label: 'TOLUCA', hub: true, type: 'HUB PRINCIPAL' },
    { id: 'met', x: 40, y: 66, label: 'METEPEC', type: 'POP' },
    { id: 'ler', x: 48, y: 52, label: 'LERMA', type: 'POP' },
    { id: 'nau', x: 72, y: 44, label: 'NAUCALPAN', hub: true, type: 'HUB' },
    { id: 'tla', x: 76, y: 36, label: 'TLALNEPANTLA', type: 'POP' },
    { id: 'eca', x: 82, y: 30, label: 'ECATEPEC', type: 'POP' },
    { id: 'hui', x: 66, y: 52, label: 'HUIXQUILUCAN', type: 'POP' },
    { id: 'atl', x: 22, y: 22, label: 'ATLACOMULCO', type: 'POP' },
    { id: 'ixt', x: 28, y: 32, label: 'IXTLAHUACA', type: 'POP' },
    { id: 'val', x: 12, y: 66, label: 'VALLE DE BRAVO', type: 'POP' },
    { id: 'oco', x: 44, y: 72, label: 'OCOYOACAC', type: 'POP' },
    { id: 'zin', x: 22, y: 64, label: 'ZINACANTEPEC', type: 'POP' },
  ];
  const edges = [
    ['tol', 'met'], ['tol', 'ler'], ['tol', 'ixt'], ['tol', 'zin'], ['tol', 'val'],
    ['ler', 'hui'], ['hui', 'nau'], ['nau', 'tla'], ['tla', 'eca'],
    ['ixt', 'atl'], ['met', 'oco'], ['nau', 'met'], ['tol', 'oco'],
  ];

  useEffect(() => {
    const id = setInterval(() => {
      const e = edges[Math.floor(Math.random() * edges.length)];
      const t = Date.now();
      setPackets(p => [...p.slice(-8), { id: t, from: e[0], to: e[1], dir: Math.random() > .5 ? 1 : -1 }]);
      setTimeout(() => setPackets(p => p.filter(x => x.id !== t)), 2400);
    }, 480);
    return () => clearInterval(id);
  }, []);

  const nodeMap = Object.fromEntries(nodes.map(n => [n.id, n]));

  return (
    <svg viewBox="0 0 100 100" preserveAspectRatio="xMidYMid meet"
         style={{ width: '100%', height: '100%', display: 'block' }}>
      <defs>
        <filter id="glow">
          <feGaussianBlur stdDeviation="0.8" result="b"/>
          <feMerge><feMergeNode in="b"/><feMergeNode in="SourceGraphic"/></feMerge>
        </filter>
      </defs>
      {/* edges */}
      {edges.map((e, i) => {
        const a = nodeMap[e[0]], b = nodeMap[e[1]];
        return <line key={i} x1={a.x} y1={a.y} x2={b.x} y2={b.y}
          stroke={accent} strokeOpacity=".28" strokeWidth=".25"
          strokeDasharray="1 .8" />;
      })}
      {/* packets */}
      {packets.map(p => {
        const a = nodeMap[p.from], b = nodeMap[p.to];
        const from = p.dir > 0 ? a : b;
        const to = p.dir > 0 ? b : a;
        return (
          <circle key={p.id} r=".7" fill={accent} filter="url(#glow)">
            <animate attributeName="cx" from={from.x} to={to.x} dur="2.2s" fill="freeze"/>
            <animate attributeName="cy" from={from.y} to={to.y} dur="2.2s" fill="freeze"/>
            <animate attributeName="opacity" values="0;1;1;0" dur="2.2s" fill="freeze"/>
          </circle>
        );
      })}
      {/* nodes */}
      {nodes.map(n => (
        <g key={n.id}>
          {n.hub && <>
            <circle cx={n.x} cy={n.y} r="3" fill="none" stroke={accent} strokeWidth=".15" opacity=".4">
              <animate attributeName="r" values="2;5;2" dur="3s" repeatCount="indefinite"/>
              <animate attributeName="opacity" values=".6;0;.6" dur="3s" repeatCount="indefinite"/>
            </circle>
          </>}
          <circle cx={n.x} cy={n.y} r={n.hub ? 1.6 : 1}
            fill={n.hub ? ink : accent}
            stroke={n.hub ? accent : 'none'}
            strokeWidth={n.hub ? '.5' : '0'}/>
          <text x={n.x + 2.5} y={n.y + .5} fontSize="1.7"
            fontFamily="'IBM Plex Mono', monospace" fontWeight="500"
            fill={ink} opacity=".7">{n.label}</text>
          {n.hub && <text x={n.x + 2.5} y={n.y + 2.8} fontSize="1.3"
            fontFamily="'IBM Plex Mono', monospace"
            fill={accent}>{n.type}</text>}
        </g>
      ))}
    </svg>
  );
}

window.NetworkGraph = NetworkGraph;
