/* ================================================================
   globe.jsx — flat, stylised dotted world map for the About page
   "institution" section. Pure 2D canvas (no WebGL), light & fast.
   - Dotted landmasses sampled from an equirectangular earth image.
   - CE-blue teardrop pins for the three offices (London, Toronto,
     Singapore), labelled.
   - Teal coverage dots for the 100+ economies, visually distinct.
   Mirrors the live site's offices map. Exports window.WorldMap.
================================================================ */

const CE_OFFICES = [
  { lat: 51.5074, lng: -0.1278, name: "London" },
  { lat: 43.6532, lng: -79.3832, name: "Toronto" },
  { lat: 1.3521, lng: 103.8198, name: "Singapore" },
];

/* Representative scatter of economies covered (capitals / financial
   centres) — a visual stand-in for "100+ economies". */
const CE_COVERAGE = [
  [38.9,-77],[40.7,-74],[45.4,-75.7],[19.4,-99.1],[14.6,-90.5],[8.98,-79.5],
  [-15.8,-47.9],[-34.6,-58.4],[-33.4,-70.6],[-12,-77],[4.7,-74.1],[10.5,-66.9],[-25.3,-57.6],
  [48.9,2.35],[52.5,13.4],[40.4,-3.7],[41.9,12.5],[52.4,4.9],[50.8,4.4],[47.4,8.5],[50.1,8.7],
  [59.3,18.1],[59.9,10.7],[52.2,21],[48.2,16.4],[55.8,37.6],[38,23.7],[38.7,-9.1],[53.3,-6.2],
  [60.2,24.9],[55.7,12.6],[50.1,14.4],[47.5,19],[44.4,26.1],[50.5,30.5],[56.9,24.1],[46.9,7.4],
  [30,31.2],[6.5,3.4],[-1.3,36.8],[-26.2,28],[33.6,-7.6],[5.6,-0.2],[9,38.7],[36.8,10.2],[14.7,-17.5],
  [24.7,46.7],[25.2,55.3],[32.1,34.8],[25.3,51.5],[41,28.9],[29.4,47.9],[26.2,50.6],[33.9,35.5],
  [39.9,116.4],[31.2,121.5],[22.3,114.2],[35.7,139.7],[37.6,127],[19.1,72.9],[28.6,77.2],
  [13.7,100.5],[-6.2,106.8],[3.1,101.7],[14.6,121],[25,121.6],[21,105.8],[24.9,67],[23.8,90.4],
  [6.9,79.9],[27.7,85.3],[-33.9,151.2],[-37.8,145],[-36.8,174.8],[-41.3,174.8],[-27.5,153],
].map(([lat, lng]) => ({ lat, lng }));

const MAP_TOP = 78, MAP_BOT = -55; // latitude crop

function WorldMap() {
  const canvasRef = React.useRef(null);
  const landRef = React.useRef([]);

  React.useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const wrap = canvas.parentElement;

    const PAD = 14;
    function project(lat, lng, scale) {
      return [PAD + (lng + 180) * scale, PAD + (MAP_TOP - lat) * scale];
    }

    function drawPin(ctx, x, y) {
      const r = 7, cy = y - 13;
      ctx.save();
      ctx.shadowColor = "rgba(60,110,230,0.65)";
      ctx.shadowBlur = 9;
      ctx.fillStyle = "#2f66e0";
      ctx.beginPath();
      ctx.moveTo(x, y);
      ctx.lineTo(x - 5, cy + 3);
      ctx.lineTo(x + 5, cy + 3);
      ctx.closePath();
      ctx.fill();
      ctx.beginPath();
      ctx.arc(x, cy, r, 0, Math.PI * 2);
      ctx.fill();
      ctx.restore();
      ctx.fillStyle = "#ffffff";
      ctx.beginPath();
      ctx.arc(x, cy, 2.6, 0, Math.PI * 2);
      ctx.fill();
    }

    function draw() {
      const dpr = Math.min(window.devicePixelRatio || 1, 2);
      const W = wrap.clientWidth;
      // Uniform scale keeps the world in true proportion; height follows width.
      const scale = (W - 2 * PAD) / 360;
      const H = Math.round((MAP_TOP - MAP_BOT) * scale + 2 * PAD);
      canvas.width = W * dpr; canvas.height = H * dpr;
      canvas.style.width = W + "px"; canvas.style.height = H + "px";
      const ctx = canvas.getContext("2d");
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
      ctx.clearRect(0, 0, W, H);

      // Landmass dots
      ctx.fillStyle = "rgba(155,172,217,0.5)";
      const land = landRef.current;
      for (let i = 0; i < land.length; i++) {
        const [x, y] = project(land[i].lat, land[i].lng, scale);
        ctx.beginPath();
        ctx.arc(x, y, 1.15, 0, Math.PI * 2);
        ctx.fill();
      }

      // Coverage dots (teal, with a soft glow)
      ctx.save();
      ctx.shadowColor = "rgba(18,179,166,0.7)";
      ctx.shadowBlur = 6;
      ctx.fillStyle = "#12b3a6";
      for (let i = 0; i < CE_COVERAGE.length; i++) {
        const [x, y] = project(CE_COVERAGE[i].lat, CE_COVERAGE[i].lng, scale);
        ctx.beginPath();
        ctx.arc(x, y, 2.7, 0, Math.PI * 2);
        ctx.fill();
      }
      ctx.restore();

      // Office pins + labels
      ctx.font = "600 12.5px system-ui, sans-serif";
      ctx.textBaseline = "middle";
      for (let i = 0; i < CE_OFFICES.length; i++) {
        const o = CE_OFFICES[i];
        const [x, y] = project(o.lat, o.lng, scale);
        drawPin(ctx, x, y);
        const right = x < W - 90;
        ctx.fillStyle = "#ffffff";
        ctx.textAlign = right ? "left" : "right";
        ctx.fillText(o.name, right ? x + 11 : x - 11, y - 15);
      }
    }

    // Sample landmasses from an equirectangular earth image (CORS-clean).
    const img = new Image();
    img.crossOrigin = "anonymous";
    img.onload = () => {
      try {
        const iw = 220, ih = 110;
        const oc = document.createElement("canvas");
        oc.width = iw; oc.height = ih;
        const octx = oc.getContext("2d");
        octx.drawImage(img, 0, 0, iw, ih);
        const data = octx.getImageData(0, 0, iw, ih).data;
        const lum = (lng, lat) => {
          const px = Math.min(iw - 1, Math.max(0, Math.floor((lng + 180) / 360 * iw)));
          const py = Math.min(ih - 1, Math.max(0, Math.floor((90 - lat) / 180 * ih)));
          const k = (py * iw + px) * 4;
          return (data[k] + data[k + 1] + data[k + 2]) / 3;
        };
        // Detect polarity using a known land (Africa) vs ocean (Pacific) point.
        const africa = lum(20, 5), pacific = lum(-150, 0);
        const landIsDark = africa < pacific;
        const thr = (africa + pacific) / 2;
        const out = [];
        const step = 2.3;
        for (let lat = MAP_BOT; lat <= MAP_TOP; lat += step) {
          for (let lng = -180; lng < 180; lng += step) {
            const L = lum(lng, lat);
            const isLand = landIsDark ? L < thr : L > thr;
            if (isLand) out.push({ lat, lng });
          }
        }
        landRef.current = out;
      } catch (e) {
        landRef.current = [];
      }
      draw();
    };
    img.onerror = () => { landRef.current = []; draw(); };
    img.src = "https://unpkg.com/three-globe@2.24.13/example/img/earth-dark.jpg";

    draw();
    let rt;
    const onResize = () => { clearTimeout(rt); rt = setTimeout(draw, 120); };
    window.addEventListener("resize", onResize);
    return () => { window.removeEventListener("resize", onResize); clearTimeout(rt); };
  }, []);

  return <canvas ref={canvasRef} style={{ display: "block", width: "100%", height: "100%" }} />;
}

window.WorldMap = WorldMap;

/* ================================================================
   MarketCircles — the brand "circles" motif, rendered inline and
   animated with a slow sinusoidal drift to suggest the fluid, moving
   state of financial markets. Full-strength brand colours. Respects
   prefers-reduced-motion and pauses when scrolled offscreen.
================================================================ */
const MARKET_CIRCLES = [
  { cx: 115.4, cy: 314.9, r: 42.3, fill: "#0C978B" },
  { cx: 200.3, cy: 238.5, r: 34.1, fill: "#5F5E5E" },
  { cx: 157.7, cy: 340.4, r: 34.2, fill: "#144392" },
  { cx: 259.8, cy: 360.4, r: 25.5, fill: "#A5B5DE" },
  { cx: 41.5, cy: 385.9, r: 21.2, fill: "#3A85C6" },
  { cx: 142.1, cy: 210.4, r: 15.6, fill: "#144392" },
  { cx: 269.2, cy: 252.7, r: 42.3, fill: "#0C978B" },
  { cx: 371.7, cy: 272.1, r: 34.1, fill: "#3A85C6" },
  { cx: 311.7, cy: 210.4, r: 34.2, fill: "#144392" },
  { cx: 447.4, cy: 238.6, r: 21.5, fill: "#144392" },
  { cx: 277.5, cy: 327.8, r: 21.2, fill: "#3A85C6" },
  { cx: 390.1, cy: 160.6, r: 15.6, fill: "#5F5E5E" },
  { cx: 436.3, cy: 135.9, r: 42.3, fill: "#3A85C6" },
  { cx: 521.1, cy: 59.5, r: 34.1, fill: "#A5B5DE" },
  { cx: 478.6, cy: 161.4, r: 34.2, fill: "#A5B5DE" },
  { cx: 555.3, cy: 181.5, r: 25.5, fill: "#0C978B" },
  { cx: 362.4, cy: 206.9, r: 21.2, fill: "#A5B5DE" },
  { cx: 463, cy: 31.4, r: 15.6, fill: "#144392" },
];

function MarketCircles({ style }) {
  const svgRef = React.useRef(null);
  React.useEffect(() => {
    const svg = svgRef.current;
    if (!svg) return;
    if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;
    const els = Array.prototype.slice.call(svg.querySelectorAll("circle"));
    const params = els.map((el, i) => ({
      ax: 7 + (i % 4) * 3,         // x drift amplitude (viewBox units)
      ay: 6 + (i % 3) * 3.5,       // y drift amplitude
      sx: 0.00017 + (i % 5) * 0.000035, // x angular speed (rad/ms)
      sy: 0.00021 + (i % 4) * 0.00004,  // y angular speed
      px: i * 1.7,
      py: i * 0.9 + 2,
    }));
    let raf = 0, visible = true, running = false;
    function frame(t) {
      if (!visible) { running = false; return; }
      raf = requestAnimationFrame(frame);
      for (let i = 0; i < els.length; i++) {
        const p = params[i];
        const dx = p.ax * Math.sin(t * p.sx + p.px);
        const dy = p.ay * Math.sin(t * p.sy + p.py);
        els[i].setAttribute("transform", "translate(" + dx.toFixed(2) + " " + dy.toFixed(2) + ")");
      }
    }
    function start() { if (!running) { running = true; raf = requestAnimationFrame(frame); } }
    const io = new IntersectionObserver((es) => { visible = es[0].isIntersecting; if (visible) start(); }, { threshold: 0.01 });
    io.observe(svg);
    start();
    return () => { cancelAnimationFrame(raf); io.disconnect(); };
  }, []);
  return (
    <svg ref={svgRef} viewBox="0 0 602 410" style={style} aria-hidden="true" xmlns="http://www.w3.org/2000/svg">
      {MARKET_CIRCLES.map((c, i) => (
        <circle key={i} cx={c.cx} cy={c.cy} r={c.r} fill={c.fill} />
      ))}
    </svg>
  );
}

window.MarketCircles = MarketCircles;
