// @wuys/map · data/centroids.js
//
// Per-country metadata. Two-tier:
//   • Country-level: full bbox, main-polygon bbox+centroid, name.
//   • POLYGON-level: per-polygon bbox, centroid, polylabel anchor + inscribed
//     circle radius. This is what drives flag-stamp placement — every
//     significant island/exclave gets its own stamp, so Indonesia / Greece /
//     UK / USA-Alaska / Russia-Kaliningrad all show flags everywhere, not just
//     on the mainland.
//
// "Significant" = polygon area >= 0.5% of the country's largest polygon, OR
// in the top 8 by area. Filters out submarine rocks while keeping every
// inhabited island. Hard cap of 12 polys per country to keep DOM count bounded
// (Canada has 389 raw polys but only ~6 are visibly significant at world view).

import { ringFromArcs } from "./topology.js";
import { shoelaceCentroid } from "../math/geodesy.js";
import { polylabel } from "./polylabel.js";
import { earClip, simplifyToCount } from "./triangulate.js";

// Target ≤ 8 vertices per polygon → ear-clipping yields ≤ 6 triangles. Across
// the whole world (~200 countries × ~5 significant polygons) that's a bounded
// ~6,000 triangles → ~24k SVG elements at 4-per-triangle. Tested OK on SVG.
const FLAG_TRIANGLE_TARGET_VERTS = 8;

const MIN_AREA_RATIO = 0.005; // polygon must be >= 0.5% of largest poly
const MAX_POLYS_PER_COUNTRY = 12;

export function computeCountryMeta(decoded, numToAlpha2) {
  const result = new Map();
  for (const geom of decoded.geometries) {
    const iso = numToAlpha2.get(String(parseInt(geom.id, 10)));
    if (!iso) continue;
    const meta = metaForGeom(geom, decoded.arcs);
    if (!meta) continue;
    meta.name = (geom.properties && geom.properties.name) || iso.toUpperCase();
    result.set(iso, meta);
  }
  return result;
}

function metaForGeom(geom, arcs) {
  const polys = geom.type === "Polygon" ? [geom.arcs]
              : geom.type === "MultiPolygon" ? geom.arcs
              : null;
  if (!polys) return null;

  // First pass: collect all polygon metadata (no polylabel yet — too expensive
  // to run on every speck). Sort by area, then run polylabel only on the ones
  // we'll keep.
  let lonMin = 180, lonMax = -180, latMin = 90, latMax = -90;
  const raw = [];
  for (const poly of polys) {
    if (!poly.length) continue;
    const points = ringFromArcs(poly[0], arcs);
    if (points.length < 3) continue;
    let pLonMin = 180, pLonMax = -180, pLatMin = 90, pLatMax = -90;
    for (const [x, y] of points) {
      if (x < pLonMin) pLonMin = x; if (x > pLonMax) pLonMax = x;
      if (y < pLatMin) pLatMin = y; if (y > pLatMax) pLatMax = y;
      if (x < lonMin) lonMin = x; if (x > lonMax) lonMax = x;
      if (y < latMin) latMin = y; if (y > latMax) latMax = y;
    }
    const c = shoelaceCentroid(points);
    if (!c || c.area === 0) continue;
    raw.push({
      points,
      area: c.area,
      lon: c.x, lat: c.y,
      lonMin: pLonMin, lonMax: pLonMax, latMin: pLatMin, latMax: pLatMax,
    });
  }
  if (raw.length === 0) return null;

  raw.sort((a, b) => b.area - a.area);
  const biggest = raw[0];
  const areaThreshold = biggest.area * MIN_AREA_RATIO;

  // Keep significant polys, cap at MAX. The largest one is always kept.
  const kept = raw
    .filter((p, i) => i === 0 || p.area >= areaThreshold)
    .slice(0, MAX_POLYS_PER_COUNTRY);

  // Run polylabel only on the polys we keep. Precision scaled to the poly's
  // size so tiny islands still resolve quickly.
  const polysMeta = kept.map((p) => {
    const span = Math.min(p.lonMax - p.lonMin, p.latMax - p.latMin);
    const precision = Math.max(0.02, span / 200);
    const pol = polylabel(p.points, precision);
    return {
      lon: p.lon, lat: p.lat,
      lonMin: p.lonMin, lonMax: p.lonMax,
      latMin: p.latMin, latMax: p.latMax,
      lonRange: p.lonMax - p.lonMin,
      latRange: p.latMax - p.latMin,
      anchorLon: pol.x,
      anchorLat: pol.y,
      anchorRadius: pol.distance,
      area: p.area,
      // Ring points (lon,lat[]) — needed by the flag layer to project a clip
      // path per polygon every frame in globe mode, so each island's flag
      // stays put under orthographic distortion.
      points: p.points,
      // Triangulation: simplify polygon ring to ≤8 verts, then ear-clip.
      // ≤6 triangles per polygon. Per-triangle 3-point affine in the flag
      // layer gives full fill + no rotation drift.
      triangles: earClip(simplifyToCount(p.points, FLAG_TRIANGLE_TARGET_VERTS)),
    };
  });

  const main = polysMeta[0];

  return {
    // Country-level (for labels / navigation / sidebar)
    lon: main.lon,
    lat: main.lat,
    lonMin, lonMax, latMin, latMax,
    lonRange: lonMax - lonMin,
    latRange: latMax - latMin,
    // Main-poly bbox (kept for backwards compat with anything that still asks)
    mainLonMin: main.lonMin, mainLonMax: main.lonMax,
    mainLatMin: main.latMin, mainLatMax: main.latMax,
    mainLonRange: main.lonRange,
    mainLatRange: main.latRange,
    flagAnchorLon: main.anchorLon,
    flagAnchorLat: main.anchorLat,
    flagAnchorRadius: main.anchorRadius,
    // NEW: per-polygon array. Flag layer iterates this and stamps every entry.
    polys: polysMeta,
  };
}
