// CAMCO v03 — world map (dot-style, Pacific-centered)
// LATAM is destination (green), with curved flow arrows from 5 source regions.
// Uses d3 + topojson-client + Natural Earth 110m countries.

const { useEffect, useRef, useState } = React;

const LATAM_IDS = new Set([
  484,                                  // Mexico
  320, 340, 222, 558, 188, 591,         // Central America + DR (excl. Cuba/HT)
  192,                                  // Cuba
  214,                                  // Dominican Rep
  332,                                  // Haiti
  388,                                  // Jamaica
  630,                                  // Puerto Rico
  170, 862, 328, 740, 254,              // CO, VE, GY, SR, FG
  218, 604, 76, 68, 600, 858, 32, 152   // EC, PE, BR, BO, PY, UY, AR, CL
]);

// Pacific-centered: Americas in the center, Asia/Oceanía to the left, Europe/Africa to the right.
const FLOWS = [
  { name: "Norteamérica", origin: [-100, 42], dest: [-102, 23],  curveDir: 1  },
  { name: "Asia",         origin: [115, 35],  dest: [-71, -30],  curveDir: -1 },
  { name: "Oceanía",      origin: [140, -25], dest: [-67, -38],  curveDir: 1  },
  { name: "Europa",       origin: [12, 50],   dest: [-43, -12],  curveDir: 1  },
  { name: "África",       origin: [22, 4],    dest: [-58, -30],  curveDir: 1  }
];

const W = 1200, H = 620;
const SPACING = 7;
const RADIUS = 1.5;
const ATLAS_URL = "https://cdn.jsdelivr.net/npm/world-atlas@2/countries-110m.json";

// Module-level cache so language toggles don't re-fetch.
let worldCache = null;

function WorldMap() {
  const ref = useRef(null);
  const [ready, setReady] = useState(false);

  useEffect(() => {
    let cancelled = false;

    (async () => {
      // Wait for d3 + topojson + the atlas
      if (typeof d3 === "undefined" || typeof topojson === "undefined") return;
      try {
        worldCache = worldCache || await fetch(ATLAS_URL).then(r => r.json());
      } catch (e) {
        console.warn("World atlas fetch failed", e);
        return;
      }
      if (cancelled || !ref.current) return;

      const world = worldCache;
      const countries = topojson.feature(world, world.objects.countries);

      // Pacific-centered Equal Earth projection
      const projection = d3.geoEqualEarth()
        .rotate([80, 0])
        .scale(225)
        .center([0, 8])
        .translate([W / 2, H / 2]);

      // Build masks via offscreen canvas to determine dot positions over land
      const offAll = document.createElement("canvas");
      offAll.width = W; offAll.height = H;
      const ctxAll = offAll.getContext("2d");
      const pathAll = d3.geoPath(projection, ctxAll);
      ctxAll.fillStyle = "#000";
      ctxAll.beginPath();
      pathAll(countries);
      ctxAll.fill();
      const allData = ctxAll.getImageData(0, 0, W, H).data;

      const latamFC = {
        type: "FeatureCollection",
        features: countries.features.filter(f => LATAM_IDS.has(+f.id))
      };
      const offLatam = document.createElement("canvas");
      offLatam.width = W; offLatam.height = H;
      const ctxLatam = offLatam.getContext("2d");
      const pathLatam = d3.geoPath(projection, ctxLatam);
      ctxLatam.fillStyle = "#000";
      ctxLatam.beginPath();
      pathLatam(latamFC);
      ctxLatam.fill();
      const latamData = ctxLatam.getImageData(0, 0, W, H).data;

      // Sample dots
      const dotsBase = [], dotsLatam = [];
      for (let y = SPACING; y < H; y += SPACING) {
        for (let x = SPACING; x < W; x += SPACING) {
          const idx = (y * W + x) * 4;
          if (allData[idx + 3] > 0) {
            const jx = (Math.random() - 0.5) * 1.2;
            const jy = (Math.random() - 0.5) * 1.2;
            const isLatam = latamData[idx + 3] > 0;
            (isLatam ? dotsLatam : dotsBase).push({ x: x + jx, y: y + jy });
          }
        }
      }

      // Wipe prior render (e.g. after language change)
      const svg = d3.select(ref.current);
      svg.selectAll("*").remove();

      // Base dots
      svg.append("g").selectAll("circle")
        .data(dotsBase).join("circle")
        .attr("cx", d => d.x).attr("cy", d => d.y).attr("r", RADIUS)
        .attr("class", "dot-base");

      // LATAM dots
      svg.append("g").selectAll("circle")
        .data(dotsLatam).join("circle")
        .attr("cx", d => d.x).attr("cy", d => d.y).attr("r", RADIUS + 0.5)
        .attr("class", "dot-latam");

      // Flow defs (arrowhead + per-flow gradients)
      const defs = svg.append("defs");
      defs.append("marker")
        .attr("id", "arrowhead-camco")
        .attr("viewBox", "0 -5 10 10")
        .attr("refX", 7).attr("refY", 0)
        .attr("markerWidth", 6).attr("markerHeight", 6)
        .attr("orient", "auto")
        .append("path")
        .attr("d", "M0,-5L10,0L0,5")
        .attr("class", "arrowhead-fill");

      const flowGeom = FLOWS.map((flow, i) => {
        const [x1, y1] = projection(flow.origin);
        const [x2, y2] = projection(flow.dest);
        const midX = (x1 + x2) / 2, midY = (y1 + y2) / 2;
        const dx = x2 - x1, dy = y2 - y1;
        const dist = Math.sqrt(dx * dx + dy * dy) || 1;
        const offsetMag = Math.min(dist * 0.28, 130);
        const cx = midX + (-dy / dist) * offsetMag * flow.curveDir;
        const cy = midY + (dx / dist) * offsetMag * flow.curveDir;

        const grad = defs.append("linearGradient")
          .attr("id", `camco-flow-grad-${i}`)
          .attr("gradientUnits", "userSpaceOnUse")
          .attr("x1", x1).attr("y1", y1)
          .attr("x2", x2).attr("y2", y2);
        grad.append("stop").attr("offset", "0%").attr("class", "flow-stop-start");
        grad.append("stop").attr("offset", "40%").attr("class", "flow-stop-mid");
        grad.append("stop").attr("offset", "100%").attr("class", "flow-stop-end");

        return { ...flow, x1, y1, x2, y2, cx, cy, gradId: `camco-flow-grad-${i}` };
      });

      const flowsGroup = svg.append("g").attr("class", "flows");

      flowGeom.forEach(f => {
        flowsGroup.append("path")
          .attr("d", `M${f.x1},${f.y1} Q${f.cx},${f.cy} ${f.x2},${f.y2}`)
          .attr("class", "flow-line")
          .attr("stroke", `url(#${f.gradId})`)
          .attr("marker-end", "url(#arrowhead-camco)");
      });

      flowGeom.forEach(f => {
        flowsGroup.append("text")
          .attr("x", f.x1).attr("y", f.y1 - 8)
          .attr("text-anchor", "middle")
          .attr("class", "label-origin")
          .text(f.name);
      });

      setReady(true);
    })();

    return () => { cancelled = true; };
  }, []);

  return (
    <div className={"world-map" + (ready ? " is-ready" : "")}>
      <svg
        ref={ref}
        className="svg-map"
        viewBox={`0 0 ${W} ${H}`}
        xmlns="http://www.w3.org/2000/svg"
        preserveAspectRatio="xMidYMid meet"
        style={{ width: "100%", height: "auto" }}
      />
    </div>
  );
}

window.WorldMap = WorldMap;
