// constellation.jsx — La carte-constellation des 38 communes de la Pévèle Carembault
// Nœuds lumineux + arcs qui pulsent à chaque Exaucement.

const COMMUNES = [
  // 38 communes Pévèle Carembault (approximation géographique normalisée 0..1)
  { n: "Orchies",            x: 0.66, y: 0.46, big: true },
  { n: "Templeuve-en-Pévèle",x: 0.42, y: 0.40, big: true },
  { n: "Cysoing",            x: 0.34, y: 0.32, big: true },
  { n: "Pont-à-Marcq",       x: 0.34, y: 0.50 },
  { n: "Phalempin",          x: 0.22, y: 0.62 },
  { n: "Thumeries",          x: 0.40, y: 0.66 },
  { n: "Ostricourt",         x: 0.28, y: 0.74 },
  { n: "Wahagnies",          x: 0.34, y: 0.70 },
  { n: "Mons-en-Pévèle",     x: 0.46, y: 0.56 },
  { n: "Mérignies",          x: 0.40, y: 0.52 },
  { n: "Avelin",             x: 0.30, y: 0.42 },
  { n: "Attiches",           x: 0.36, y: 0.58 },
  { n: "Ennevelin",          x: 0.42, y: 0.46 },
  { n: "Tourmignies",        x: 0.32, y: 0.56 },
  { n: "Moncheaux",          x: 0.40, y: 0.74 },
  { n: "Genech",             x: 0.42, y: 0.32 },
  { n: "Bachy",              x: 0.46, y: 0.22 },
  { n: "Cobrieux",           x: 0.40, y: 0.26 },
  { n: "Bourghelles",        x: 0.32, y: 0.26 },
  { n: "Wannehain",          x: 0.46, y: 0.28 },
  { n: "Mouchin",            x: 0.50, y: 0.30 },
  { n: "Louvil",             x: 0.36, y: 0.28 },
  { n: "Bersée",             x: 0.46, y: 0.46 },
  { n: "Bouvignies",         x: 0.62, y: 0.54 },
  { n: "Coutiches",          x: 0.56, y: 0.58 },
  { n: "Beuvry-la-Forêt",    x: 0.74, y: 0.52 },
  { n: "Auchy-lez-Orchies",  x: 0.62, y: 0.42 },
  { n: "Landas",             x: 0.74, y: 0.40 },
  { n: "Nomain",             x: 0.62, y: 0.34 },
  { n: "Saméon",             x: 0.78, y: 0.34 },
  { n: "Aix-en-Pévèle",      x: 0.54, y: 0.40 },
  { n: "Cappelle-en-Pévèle", x: 0.50, y: 0.46 },
  { n: "Chemy",              x: 0.20, y: 0.54 },
  { n: "La Neuville",        x: 0.24, y: 0.46 },
  { n: "Faumont",            x: 0.56, y: 0.66 },
  { n: "Rosult",             x: 0.84, y: 0.42 },
  { n: "Tilloy-lez-Marchiennes", x: 0.86, y: 0.50 },
  { n: "Marchiennes",        x: 0.86, y: 0.58 },
];

// Pseudo-random but deterministic graph of "connections" (lignes lumineuses entre communes voisines)
function buildEdges(nodes) {
  const edges = [];
  nodes.forEach((a, i) => {
    // Connect each node to its 2-3 closest neighbors
    const sorted = nodes
      .map((b, j) => ({ b, j, d: Math.hypot(a.x - b.x, a.y - b.y) }))
      .filter(o => o.j !== i)
      .sort((x, y) => x.d - y.d)
      .slice(0, 2 + (i % 2));
    sorted.forEach(({ j }) => {
      const key = [Math.min(i, j), Math.max(i, j)].join("-");
      if (!edges.find(e => e.key === key)) {
        edges.push({ key, i: Math.min(i, j), j: Math.max(i, j) });
      }
    });
  });
  return edges;
}

const EDGES = buildEdges(COMMUNES);

function Constellation({ variant = "hero", showLabels = "few" }) {
  // variant: "hero" (large), "compact"
  // showLabels: "all" | "few" | "none"
  const W = 1000, H = 750;
  const [pulses, setPulses] = React.useState([]); // active arc pulses
  const [activeNode, setActiveNode] = React.useState(null);
  const idRef = React.useRef(0);

  // Trigger random "exaucement" pulses
  React.useEffect(() => {
    const reduced = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
    if (reduced) return;
    const interval = setInterval(() => {
      const edge = EDGES[Math.floor(Math.random() * EDGES.length)];
      const id = ++idRef.current;
      setPulses(p => [...p, { id, ...edge, t: Date.now() }]);
      setActiveNode(Math.random() < 0.5 ? edge.i : edge.j);
      setTimeout(() => {
        setPulses(p => p.filter(x => x.id !== id));
      }, 2400);
    }, 900);
    return () => clearInterval(interval);
  }, []);

  return (
    <div className="constellation-wrap" aria-label="Carte constellation de la Pévèle Carembault — 38 communes">
      <svg viewBox={`0 0 ${W} ${H}`} preserveAspectRatio="xMidYMid meet">
        <defs>
          <radialGradient id="haloViolet" cx="50%" cy="50%" r="50%">
            <stop offset="0%" stopColor="#7C5CFF" stopOpacity="0.5" />
            <stop offset="60%" stopColor="#7C5CFF" stopOpacity="0.1" />
            <stop offset="100%" stopColor="#7C5CFF" stopOpacity="0" />
          </radialGradient>
          <radialGradient id="haloCyan" cx="50%" cy="50%" r="50%">
            <stop offset="0%" stopColor="#22D3EE" stopOpacity="0.45" />
            <stop offset="60%" stopColor="#22D3EE" stopOpacity="0.08" />
            <stop offset="100%" stopColor="#22D3EE" stopOpacity="0" />
          </radialGradient>
          <linearGradient id="edgeGrad" x1="0" y1="0" x2="1" y2="1">
            <stop offset="0%" stopColor="#7C5CFF" stopOpacity="0.5" />
            <stop offset="100%" stopColor="#22D3EE" stopOpacity="0.5" />
          </linearGradient>
          <linearGradient id="pulseGrad" x1="0" y1="0" x2="1" y2="0">
            <stop offset="0%" stopColor="#F5B544" stopOpacity="0" />
            <stop offset="50%" stopColor="#F5B544" stopOpacity="1" />
            <stop offset="100%" stopColor="#F5B544" stopOpacity="0" />
          </linearGradient>
          <radialGradient id="nodeGlow" cx="50%" cy="50%" r="50%">
            <stop offset="0%" stopColor="#fff" stopOpacity="1" />
            <stop offset="40%" stopColor="#22D3EE" stopOpacity="0.6" />
            <stop offset="100%" stopColor="#22D3EE" stopOpacity="0" />
          </radialGradient>
          <radialGradient id="nodeGlowGold" cx="50%" cy="50%" r="50%">
            <stop offset="0%" stopColor="#fff" stopOpacity="1" />
            <stop offset="30%" stopColor="#F5B544" stopOpacity="0.9" />
            <stop offset="100%" stopColor="#F5B544" stopOpacity="0" />
          </radialGradient>
          <filter id="softBlur" x="-50%" y="-50%" width="200%" height="200%">
            <feGaussianBlur stdDeviation="1.5" />
          </filter>
        </defs>

        {/* Ambient halos */}
        <ellipse cx={W * 0.42} cy={H * 0.42} rx="320" ry="220" fill="url(#haloViolet)" />
        <ellipse cx={W * 0.68} cy={H * 0.5} rx="280" ry="220" fill="url(#haloCyan)" />

        {/* Subtle territory contour */}
        <path
          d={`M ${W*0.12},${H*0.5} 
              Q ${W*0.18},${H*0.18} ${W*0.4},${H*0.16}
              Q ${W*0.65},${H*0.14} ${W*0.85},${H*0.26}
              Q ${W*0.95},${H*0.45} ${W*0.88},${H*0.65}
              Q ${W*0.7},${H*0.86} ${W*0.42},${H*0.82}
              Q ${W*0.15},${H*0.78} ${W*0.12},${H*0.5} Z`}
          fill="none"
          stroke="rgba(255,255,255,0.05)"
          strokeWidth="1"
          strokeDasharray="2,6"
        />

        {/* Edges (constellation lines) */}
        {EDGES.map(e => {
          const a = COMMUNES[e.i], b = COMMUNES[e.j];
          return (
            <line
              key={e.key}
              x1={a.x * W} y1={a.y * H}
              x2={b.x * W} y2={b.y * H}
              stroke="url(#edgeGrad)"
              strokeWidth="0.6"
              opacity="0.35"
            />
          );
        })}

        {/* Pulse arcs */}
        {pulses.map(p => {
          const a = COMMUNES[p.i], b = COMMUNES[p.j];
          const x1 = a.x * W, y1 = a.y * H;
          const x2 = b.x * W, y2 = b.y * H;
          // Curve via midpoint offset
          const mx = (x1 + x2) / 2;
          const my = (y1 + y2) / 2;
          const dx = x2 - x1, dy = y2 - y1;
          const len = Math.hypot(dx, dy);
          const cx = mx - (dy / len) * (len * 0.25);
          const cy = my - (-dx / len) * (len * 0.25);
          return (
            <g key={p.id}>
              <path
                d={`M ${x1},${y1} Q ${cx},${cy} ${x2},${y2}`}
                fill="none"
                stroke="#F5B544"
                strokeWidth="1.5"
                strokeLinecap="round"
                opacity="0.9"
                style={{
                  filter: "drop-shadow(0 0 4px #F5B544)",
                  strokeDasharray: 1000,
                  strokeDashoffset: 1000,
                  animation: "drawArc 2.4s cubic-bezier(0.22,1,0.36,1) forwards",
                }}
              />
              {/* Spark traveling along arc */}
              <circle r="3.5" fill="#fff" style={{
                filter: "drop-shadow(0 0 6px #F5B544)",
                animation: "travelArc 1.4s cubic-bezier(0.4,0,0.2,1) forwards",
                offsetPath: `path('M ${x1},${y1} Q ${cx},${cy} ${x2},${y2}')`,
              }} />
            </g>
          );
        })}

        {/* Nodes (38 communes) */}
        {COMMUNES.map((c, i) => {
          const cx = c.x * W, cy = c.y * H;
          const isActive = activeNode === i;
          const r = c.big ? 4.5 : 3;
          return (
            <g key={i}>
              {/* Outer glow */}
              <circle
                cx={cx} cy={cy}
                r={r * 4}
                fill={isActive ? "url(#nodeGlowGold)" : "url(#nodeGlow)"}
                opacity={isActive ? 0.85 : 0.32}
                style={{ transition: "opacity 600ms cubic-bezier(0.22,1,0.36,1)" }}
              />
              {/* Core */}
              <circle
                cx={cx} cy={cy}
                r={r}
                fill="#ffffff"
                style={{
                  filter: isActive
                    ? "drop-shadow(0 0 8px #F5B544)"
                    : "drop-shadow(0 0 3px rgba(34,211,238,0.6))",
                  transition: "filter 600ms",
                }}
              />
              {/* Pulse ring */}
              <circle
                cx={cx} cy={cy}
                r={r}
                fill="none"
                stroke={isActive ? "#F5B544" : "rgba(255,255,255,0.4)"}
                strokeWidth="0.5"
                style={{
                  transformOrigin: `${cx}px ${cy}px`,
                  animation: `ringPulse 3.5s ${(i * 0.13) % 3}s infinite`,
                }}
              />
              {/* Labels */}
              {(showLabels === "all" || (showLabels === "few" && c.big)) && (
                <text
                  x={cx + r + 6}
                  y={cy + 3}
                  className="node-label"
                >
                  {c.n}
                </text>
              )}
            </g>
          );
        })}
      </svg>

      <style>{`
        @keyframes drawArc {
          0% { stroke-dashoffset: 1000; opacity: 0; }
          15% { opacity: 1; }
          40% { stroke-dashoffset: 0; opacity: 1; }
          100% { stroke-dashoffset: 0; opacity: 0; }
        }
        @keyframes travelArc {
          0% { offset-distance: 0%; opacity: 0; }
          15% { opacity: 1; }
          90% { offset-distance: 100%; opacity: 1; }
          100% { offset-distance: 100%; opacity: 0; }
        }
        @keyframes ringPulse {
          0% { transform: scale(1); opacity: 0.6; }
          70% { transform: scale(3); opacity: 0; }
          100% { transform: scale(3); opacity: 0; }
        }
      `}</style>
    </div>
  );
}

window.Constellation = Constellation;
window.COMMUNES = COMMUNES;
window.EDGES = EDGES;
