/* global React */
// ============================================================
// FeatureGlobe — realistic orthographic Earth for the
// "Pagos globales" feature. Same rendering vocabulary as the
// SPEI Global section's <Globe/> (deep-blue sphere, real
// land/borders/graticule from world-atlas, pulsing city nodes
// + flowing arcs), but ZOOMED so the planet bleeds subtly past
// the window edges, and rotating noticeably faster.
// ============================================================
const { useEffect: fgUseEffect, useRef: fgUseRef, useState: fgUseState } = React;

// City nodes — [lon, lat]
const FG_NODES = [
  { id: "mex", coord: [-99.13, 19.43] },
  { id: "nyc", coord: [-74.01, 40.71] },
  { id: "sao", coord: [-46.63, -23.55] },
  { id: "lon", coord: [-0.13, 51.51] },
  { id: "mad", coord: [-3.70, 40.42] },
  { id: "dub", coord: [55.27, 25.20] },
  { id: "sin", coord: [103.82, 1.35] },
  { id: "hkg", coord: [114.17, 22.32] },
  { id: "tyo", coord: [139.69, 35.69] },
  { id: "syd", coord: [151.21, -33.87] },
  { id: "jnb", coord: [28.04, -26.20] },
];
const FG_ARCS = [
  { from: "mex", to: "lon", delay: 0.0, dur: 5.0 },
  { from: "nyc", to: "tyo", delay: 0.8, dur: 5.4 },
  { from: "mad", to: "sao", delay: 1.6, dur: 4.6 },
  { from: "lon", to: "sin", delay: 2.3, dur: 5.2 },
  { from: "hkg", to: "syd", delay: 3.0, dur: 4.4 },
  { from: "mex", to: "hkg", delay: 3.8, dur: 5.4 },
  { from: "dub", to: "jnb", delay: 4.5, dur: 4.2 },
  { from: "nyc", to: "mad", delay: 5.2, dur: 4.8 },
];

let _fgWorldPromise = null;
function fgLoadWorld() {
  if (_fgWorldPromise) return _fgWorldPromise;
  _fgWorldPromise = fetch("https://cdn.jsdelivr.net/npm/world-atlas@2.0.2/countries-110m.json")
    .then((r) => r.json())
    .then((topo) => {
      const topojson = window.topojson;
      return {
        land: topojson.feature(topo, topo.objects.land),
        borders: topojson.mesh(topo, topo.objects.countries, (a, b) => a !== b),
      };
    });
  return _fgWorldPromise;
}

function FeatureGlobe() {
  const landRef = fgUseRef(null);
  const bordersRef = fgUseRef(null);
  const graticuleRef = fgUseRef(null);
  const sphereRef = fgUseRef(null);
  const nodesGroupRef = fgUseRef(null);
  const arcsGroupRef = fgUseRef(null);
  const cometsGroupRef = fgUseRef(null);

  const [ready, setReady] = fgUseState(false);

  fgUseEffect(() => {
    let mounted = true;
    let rafId = null;
    const startMs = performance.now();

    const W = 400, H = 400, R = 206;   // R > 200 → sphere bleeds past the viewBox edges
    const CX = W / 2, CY = H / 2;

    const d3 = window.d3;
    if (!d3 || !window.topojson) return;

    const projection = d3.geoOrthographic().scale(R).translate([CX, CY]).clipAngle(90);
    const pathGen = d3.geoPath(projection);
    const graticule = d3.geoGraticule().step([15, 15])();

    function buildNodes() {
      const g = nodesGroupRef.current;
      if (!g) return [];
      g.innerHTML = "";
      const ns = "http://www.w3.org/2000/svg";
      return FG_NODES.map((_, i) => {
        const wrap = document.createElementNS(ns, "g");
        const halo = document.createElementNS(ns, "circle");
        halo.setAttribute("r", "4.5");
        halo.setAttribute("fill", "rgba(140,160,246,0.22)");
        halo.setAttribute("class", "node-halo");
        halo.setAttribute("style", `animation-delay:${(i * 0.32).toFixed(2)}s;`);
        const pulse = document.createElementNS(ns, "circle");
        pulse.setAttribute("r", "3");
        pulse.setAttribute("fill", "none");
        pulse.setAttribute("stroke", "rgba(140,160,246,0.95)");
        pulse.setAttribute("stroke-width", "1");
        pulse.setAttribute("class", "node-pulse");
        pulse.setAttribute("style", `animation-delay:${(i * 0.32).toFixed(2)}s;`);
        const outer = document.createElementNS(ns, "circle");
        outer.setAttribute("r", "2.6");
        outer.setAttribute("fill", "#ffffff");
        const inner = document.createElementNS(ns, "circle");
        inner.setAttribute("r", "1.3");
        inner.setAttribute("fill", "#5A74EC");
        wrap.appendChild(halo); wrap.appendChild(pulse);
        wrap.appendChild(outer); wrap.appendChild(inner);
        g.appendChild(wrap);
        return wrap;
      });
    }

    let world = null, nodeEls = [];
    const byId = Object.fromEntries(FG_NODES.map((n) => [n.id, n.coord]));

    fgLoadWorld().then((w) => {
      if (!mounted) return;
      world = w;
      nodeEls = buildNodes();
      setReady(true);
      if (sphereRef.current) sphereRef.current.setAttribute("d", pathGen({ type: "Sphere" }) || "");
      rafId = requestAnimationFrame(tick);
    }).catch(() => {});

    function tick(now) {
      if (!mounted) return;
      const t = (now - startMs) / 1000;
      // Start facing the Americas (centre ≈ 90°W) then drift east, slowly.
      const lambda = 90 - t * 9;               // ~40s per rotation — smoother
      projection.rotate([lambda, -16, 0]);

      if (landRef.current) landRef.current.setAttribute("d", pathGen(world.land) || "");
      if (bordersRef.current) bordersRef.current.setAttribute("d", pathGen(world.borders) || "");
      if (graticuleRef.current) graticuleRef.current.setAttribute("d", pathGen(graticule) || "");

      const center = projection.invert([CX, CY]);
      for (let i = 0; i < FG_NODES.length; i++) {
        const el = nodeEls[i]; if (!el) continue;
        const coord = FG_NODES[i].coord;
        const dist = d3.geoDistance(coord, center);
        if (dist < Math.PI / 2 - 0.03) {
          const xy = projection(coord);
          if (xy) {
            el.setAttribute("transform", `translate(${xy[0]} ${xy[1]})`);
            const edge = 1 - dist / (Math.PI / 2);
            el.setAttribute("opacity", Math.min(1, edge * 4).toFixed(3));
          }
        } else { el.setAttribute("opacity", "0"); }
      }

      rafId = requestAnimationFrame(tick);
    }

    return () => { mounted = false; if (rafId) cancelAnimationFrame(rafId); };
  }, []);

  return (
    <div className="fg-wrap">
      <svg className="fg-svg" viewBox="0 0 400 400" preserveAspectRatio="xMidYMid slice" aria-hidden="true">
        <defs>
          <radialGradient id="fg-sphere" cx="35%" cy="30%" r="80%">
            <stop offset="0%" stopColor="#1f4694"/>
            <stop offset="35%" stopColor="#0d2563"/>
            <stop offset="75%" stopColor="#06143e"/>
            <stop offset="100%" stopColor="#020722"/>
          </radialGradient>
          <radialGradient id="fg-shine" cx="30%" cy="22%" r="40%">
            <stop offset="0%" stopColor="rgba(160,195,255,0.55)"/>
            <stop offset="55%" stopColor="rgba(160,195,255,0.05)"/>
            <stop offset="100%" stopColor="rgba(160,195,255,0)"/>
          </radialGradient>
          <radialGradient id="fg-rim" cx="50%" cy="50%" r="50%">
            <stop offset="62%" stopColor="rgba(0,0,0,0)"/>
            <stop offset="100%" stopColor="rgba(0,0,0,0.5)"/>
          </radialGradient>
          <clipPath id="fg-clip"><circle cx="200" cy="200" r="206"/></clipPath>
        </defs>

        <circle cx="200" cy="200" r="206" fill="url(#fg-sphere)"/>

        <g clipPath="url(#fg-clip)">
          <path ref={graticuleRef} fill="none" stroke="rgba(140,160,246,0.18)" strokeWidth="0.45"/>
          <path ref={sphereRef} fill="none" stroke="rgba(140,160,246,0.25)" strokeWidth="0.6"/>
          <path ref={landRef} fill="rgba(102,148,235,0.55)" stroke="rgba(190,215,255,0.85)" strokeWidth="0.5" strokeLinejoin="round"/>
          <path ref={bordersRef} fill="none" stroke="rgba(220,235,255,0.45)" strokeWidth="0.35"/>
          <circle cx="200" cy="200" r="206" fill="url(#fg-rim)"/>
          <circle cx="200" cy="200" r="206" fill="url(#fg-shine)"/>
          <g ref={nodesGroupRef}/>
        </g>
      </svg>

      {!ready && (
        <div className="globe-loading" aria-hidden="true">
          <span className="globe-loading-dot"/><span className="globe-loading-dot"/><span className="globe-loading-dot"/>
        </div>
      )}

      <style>{`
        .fg-wrap{position:absolute;inset:0;overflow:hidden;}
        /* Anchored to the right and oversized so the planet bleeds off the
           top/bottom and right edges, leaving open space on the left. */
        .fg-svg{position:absolute;top:50%;right:-1%;transform:translateY(-50%);
          height:124%;aspect-ratio:1/1;width:auto;display:block;}
        .fg-wrap .globe-loading{position:absolute;inset:0;}
      `}</style>
    </div>
  );
}

window.FeatureGlobe = FeatureGlobe;
