/* global React */
// World map — stylized dot-grid mercator projection.
// Generated at runtime from a small set of continent polygons.
// Plots heat by country (data-heat) and animated pings for active locations.

const CC_MAP = (() => {
  const W = 1000, H = 500;

  // ---- Mercator projection (lon, lat) -> (x, y) ----
  function project(lon, lat) {
    const x = ((lon + 180) / 360) * W;
    const latRad = (Math.max(-78, Math.min(78, lat)) * Math.PI) / 180;
    const mercY = Math.log(Math.tan(Math.PI / 4 + latRad / 2));
    // map mercY from about [-2.5, 2.5] -> [H, 0]
    const y = H / 2 - (mercY * H) / 5;
    return [x, y];
  }

  // ---- Continent polygons (lon, lat) ----
  // Loose hand-drawn outlines — recognizable world shape without being geographically precise.
  const POLYS = [
    // North America (main)
    [[-168,66],[-160,71],[-141,70],[-128,70],[-114,68],[-100,68],[-85,69],[-78,72],[-65,60],[-58,52],[-65,46],[-67,44],[-71,41],[-75,36],[-81,31],[-81,25],[-86,30],[-89,29],[-94,29],[-97,26],[-99,20],[-105,20],[-115,30],[-124,33],[-130,40],[-128,49],[-132,55],[-138,60],[-152,60],[-160,55],[-168,60]],
    // Greenland
    [[-50,60],[-44,60],[-22,70],[-22,82],[-40,83],[-55,80],[-58,72],[-55,65]],
    // South America
    [[-81,11],[-74,12],[-60,11],[-50,5],[-35,-5],[-39,-15],[-37,-22],[-44,-25],[-48,-30],[-58,-39],[-65,-43],[-71,-54],[-73,-50],[-72,-43],[-72,-36],[-71,-30],[-71,-20],[-78,-10],[-81,-2],[-78,3],[-82,8]],
    // Europe + W Asia + N Africa + Middle East + Africa (Afro-Eurasia western blob)
    [[-10,36],[-9,43],[-4,48],[2,51],[6,53],[8,58],[12,58],[15,56],[18,56],[24,60],[28,60],[24,66],[28,70],[34,69],[40,68],[55,70],[68,70],[78,73],[100,76],[110,74],[140,72],[160,70],[178,71],[180,66],[170,60],[160,58],[140,55],[133,46],[140,38],[143,35],[140,32],[122,28],[110,18],[105,10],[100,8],[100,4],[105,1],[103,1],[100,-3],[105,-7],[114,-9],[124,-9],[126,-3],[135,-4],[150,-7],[155,-10],[152,-3],[145,1],[140,5],[135,8],[126,18],[121,22],[110,22],[100,30],[90,30],[80,32],[68,38],[55,40],[44,38],[38,40],[42,30],[44,25],[55,18],[50,12],[51,2],[42,-1],[40,-12],[40,-24],[35,-30],[27,-34],[20,-34],[17,-30],[14,-22],[12,-12],[9,-5],[5,2],[-1,5],[-7,5],[-15,12],[-17,21],[-16,28],[-10,34],[-9,36]],
    // Australia
    [[114,-22],[122,-18],[131,-12],[136,-12],[140,-17],[145,-15],[147,-19],[153,-25],[151,-32],[146,-38],[140,-37],[131,-32],[123,-34],[115,-34],[113,-28],[114,-22]],
    // New Zealand (two islands)
    [[166,-46],[170,-43],[174,-41],[173,-37],[178,-37],[174,-35],[172,-39],[168,-45],[166,-46]],
    // Japan
    [[131,33],[136,35],[140,38],[142,42],[145,44],[141,45],[136,37],[131,33]],
    // UK + Ireland
    [[-10,52],[-6,55],[-2,58],[1,58],[2,52],[-2,50],[-6,50],[-10,52]],
    // Iceland
    [[-24,64],[-13,64],[-13,67],[-22,67],[-24,64]],
    // Madagascar
    [[43,-25],[50,-23],[49,-15],[44,-12],[43,-19],[43,-25]],
    // Indonesia spread
    [[95,5],[105,5],[110,1],[100,-3],[95,5]],
    [[112,-7],[124,-8],[124,-3],[112,-7]],
    // Philippines
    [[118,8],[126,18],[122,10],[120,5],[118,8]],
    // Sri Lanka
    [[79,7],[82,8],[82,5],[79,7]],
    // Cuba etc Caribbean
    [[-85,21],[-74,21],[-74,18],[-85,18],[-85,21]],
    // Hispaniola
    [[-74,18],[-68,18],[-68,20],[-74,20],[-74,18]],
  ];

  function pointInPoly(px, py, poly) {
    let inside = false;
    for (let i = 0, j = poly.length - 1; i < poly.length; j = i++) {
      const xi = poly[i][0], yi = poly[i][1];
      const xj = poly[j][0], yj = poly[j][1];
      const intersect = ((yi > py) !== (yj > py)) &&
        (px < ((xj - xi) * (py - yi)) / (yj - yi + 1e-9) + xi);
      if (intersect) inside = !inside;
    }
    return inside;
  }

  function isLand(lon, lat) {
    for (let i = 0; i < POLYS.length; i++) {
      if (pointInPoly(lon, lat, POLYS[i])) return true;
    }
    return false;
  }

  // ---- Build a dot grid ----
  function buildDots(cols = 110, rows = 50) {
    const dots = [];
    for (let r = 0; r < rows; r++) {
      for (let c = 0; c < cols; c++) {
        const lon = -180 + ((c + 0.5) / cols) * 360;
        const lat = 85 - ((r + 0.5) / rows) * 165;
        if (isLand(lon, lat)) {
          const [x, y] = project(lon, lat);
          dots.push({ x, y, lon, lat });
        }
      }
    }
    return dots;
  }

  return { W, H, project, buildDots };
})();


function CcWorldMap({ heatByCountry = {}, centroids = {}, pings = [] }) {
  const dots = React.useMemo(() => CC_MAP.buildDots(140, 60), []);

  // Heat scale 1-5 → color/opacity
  const heatColor = (level) => {
    const base = [0.10, 0.20, 0.34, 0.55, 0.78, 1.0];
    return `rgba(184, 96, 42, ${base[level] || 0.10})`;
  };

  // Convert country heat to dot color near centroid
  const dotHeat = React.useMemo(() => {
    // For each dot, find closest centroid within radius, and inherit heat
    const heatPoints = Object.entries(heatByCountry).map(([iso, lvl]) => {
      const c = centroids[iso];
      if (!c) return null;
      return { iso, lvl, lon: c[0], lat: c[1] };
    }).filter(Boolean);

    return dots.map((d) => {
      let best = 0;
      let bestDist = Infinity;
      for (const hp of heatPoints) {
        const dx = d.lon - hp.lon;
        const dy = d.lat - hp.lat;
        const dist = dx * dx + dy * dy;
        const radius = 24 * 24 * (hp.lvl + 1);
        if (dist < radius && dist < bestDist) {
          bestDist = dist;
          // attenuate by distance
          const falloff = 1 - Math.sqrt(dist) / (24 * (hp.lvl + 1));
          best = Math.max(best, hp.lvl * falloff);
        }
      }
      return Math.round(best);
    });
  }, [dots, heatByCountry, centroids]);

  return (
    <div className="cc-map-wrap">
      <svg className="cc-map-svg" viewBox={`0 0 ${CC_MAP.W} ${CC_MAP.H}`} preserveAspectRatio="xMidYMid meet">
        {/* dot grid */}
        <g>
          {dots.map((d, i) => {
            const h = dotHeat[i];
            const r = 1.6 + h * 0.35;
            const opacity = 0.18 + h * 0.16;
            const color = h > 0 ? heatColor(Math.min(5, Math.round(h + 1))) : 'rgba(58, 38, 20, 0.22)';
            return (
              <circle key={i} cx={d.x} cy={d.y} r={r} fill={color} opacity={opacity + 0.4}>
                {h >= 3 && (
                  <animate attributeName="opacity"
                    values={`${opacity + 0.2};${opacity + 0.8};${opacity + 0.2}`}
                    dur="3s" repeatCount="indefinite" begin={`${(i % 17) * 0.18}s`} />
                )}
              </circle>
            );
          })}
        </g>

        {/* pings at top-heat countries */}
        {pings.map((iso, i) => {
          const c = centroids[iso];
          if (!c) return null;
          const [x, y] = CC_MAP.project(c[0], c[1]);
          return (
            <g key={iso}>
              <circle cx={x} cy={y} r="3" fill="var(--color-accent)" style={{ filter: 'drop-shadow(0 0 4px rgba(184,96,42,0.7))' }} />
              <circle cx={x} cy={y} r="4" fill="none" stroke="var(--color-accent)" strokeWidth="1.2" opacity="0.7">
                <animate attributeName="r" from="3" to="22" dur="2.4s" repeatCount="indefinite" begin={`${i * 0.4}s`} />
                <animate attributeName="opacity" from="0.7" to="0" dur="2.4s" repeatCount="indefinite" begin={`${i * 0.4}s`} />
              </circle>
            </g>
          );
        })}
      </svg>

      {/* heat legend */}
      <div className="cc-map-legend">
        <span>low</span>
        <div className="cc-map-legend-bar">
          <div className="cc-map-legend-step" style={{ background: 'rgba(184,96,42,0.18)' }}></div>
          <div className="cc-map-legend-step" style={{ background: 'rgba(184,96,42,0.35)' }}></div>
          <div className="cc-map-legend-step" style={{ background: 'rgba(184,96,42,0.55)' }}></div>
          <div className="cc-map-legend-step" style={{ background: 'rgba(184,96,42,0.78)' }}></div>
          <div className="cc-map-legend-step" style={{ background: 'rgba(184,96,42,0.95)' }}></div>
        </div>
        <span>high</span>
      </div>
    </div>
  );
}

window.CcWorldMap = CcWorldMap;
