// globe.jsx — Wireframe globe rendered to a 2D canvas. Auto-rotating.

const { useEffect, useRef, useState } = React;

// Low-poly coastline approximation per region: [lat, lng] pairs.
const COAST = [
  // South America
  [[12,-72],[8,-77],[-2,-80],[-12,-77],[-18,-71],[-23,-71],[-33,-72],[-40,-73],[-50,-75],[-55,-68],[-53,-58],[-42,-65],[-38,-58],[-34,-58],[-30,-54],[-23,-43],[-15,-39],[-5,-35],[1,-46],[5,-52],[8,-60],[10,-66],[12,-72]],
  // North America (rough)
  [[15,-92],[18,-96],[22,-105],[28,-112],[33,-117],[38,-122],[48,-124],[55,-130],[60,-140],[65,-150],[70,-156],[71,-130],[68,-110],[60,-95],[50,-90],[42,-82],[40,-74],[30,-80],[25,-80],[18,-90],[15,-92]],
  // Europe / Africa west coast
  [[58,5],[55,12],[50,1],[44,-4],[38,-9],[36,-6],[31,-9],[24,-15],[16,-17],[10,-15],[5,-9],[0,3],[-5,11],[-12,13],[-22,14],[-30,18],[-34,18],[-30,30],[-22,35],[-12,40],[0,42],[10,43],[20,38],[30,32],[36,36],[40,26],[45,28],[50,30],[55,30],[60,28]],
  // Asia rough
  [[60,55],[55,75],[50,90],[55,110],[60,130],[68,150],[70,170],[60,160],[40,140],[35,135],[30,120],[22,110],[10,100],[1,103],[-8,115],[-10,125],[-8,140]],
  // Australia
  [[-12,130],[-18,122],[-22,114],[-32,116],[-35,118],[-38,140],[-37,148],[-32,153],[-25,153],[-18,146],[-12,135],[-12,130]],
];

function HeroGlobe({ size = 460 }) {
  const ref = useRef(null);
  const hovering = useRef(false);
  const yaw = useRef(0);
  const pitch = useRef(-0.05);
  const yawT = useRef(0);
  const pitchT = useRef(-0.05);
  const [pinVis, setPinVis] = useState(false);
  const [pins, setPins] = useState([]);

  // São Paulo: operations. Wilmington, Delaware: holding entity.
  const LOCATIONS = [
    { id:"sp", lat:-23.55, lng:-46.63, mark:"São Paulo",  coord:"Operations · −23.55, −46.63",  primary:true },
    { id:"de", lat: 39.16, lng:-75.52, mark:"Delaware",   coord:"Wilmington · 39.16, −75.52",    primary:false },
  ];

  useEffect(() => {
    const c = ref.current; if (!c) return;
    const ctx = c.getContext("2d");
    let raf;
    function resize() {
      const dpr = Math.min(window.devicePixelRatio || 1, 2);
      const w = c.clientWidth, h = c.clientHeight;
      c.width = w * dpr; c.height = h * dpr;
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
    }
    const ro = new ResizeObserver(resize); ro.observe(c); resize();

    // Convert (lat, lng) -> 3D unit vector using standard astronomical
    // convention: +x = east (right), +y = north (up), +z = toward viewer.
    // yawA rotates around Y, pitchA tilts around X.
    function latLngToVec3(lat, lng, yawA, pitchA) {
      const phi   = lat * Math.PI / 180;
      const theta = lng * Math.PI / 180 + yawA;
      let x = Math.cos(phi) * Math.sin(theta);
      let y = Math.sin(phi);
      let z = Math.cos(phi) * Math.cos(theta);
      // pitch around X axis
      const cy = Math.cos(pitchA), sy = Math.sin(pitchA);
      const y2 = y * cy - z * sy;
      const z2 = y * sy + z * cy;
      return [x, y2, z2];
    }
    // Project to 2D (orthographic-ish with slight perspective)
    function project(v, cx, cy, R) {
      const persp = 1 / (1.4 - v[2] * 0.55);
      return { x: cx + v[0] * R * persp, y: cy - v[1] * R * persp, z: v[2] };
    }

    // Focus camera between the two pins on hover.
    const SP_LAT = -23.55, SP_LNG = -46.63;
    const DE_LAT = 39.16,  DE_LNG = -75.52;
    const MID_LNG = (SP_LNG + DE_LNG) / 2;
    const FOCUS_YAW   = (-MID_LNG) * Math.PI / 180;
    const FOCUS_PITCH = ((SP_LAT + DE_LAT) / 2 * 0.3) * Math.PI / 180;

    function tick() {
      const w = c.clientWidth, h = c.clientHeight;
      ctx.clearRect(0, 0, w, h);
      if (hovering.current) {
        yawT.current = FOCUS_YAW;
        pitchT.current = FOCUS_PITCH;
      } else {
        yawT.current += 0.003;
        pitchT.current = -0.05;
      }
      // Smooth toward targets (slower for snappy-but-smooth)
      yaw.current   += (yawT.current   - yaw.current)   * 0.05;
      pitch.current += (pitchT.current - pitch.current) * 0.06;

      const cx = w / 2, cy = h / 2;
      const R = Math.min(w, h) * 0.40;

      // 1) Sphere outline (a faint disc edge)
      ctx.strokeStyle = "rgba(245,243,238,.14)";
      ctx.lineWidth = 1;
      ctx.beginPath(); ctx.arc(cx, cy, R, 0, Math.PI * 2); ctx.stroke();

      // 2) Inner disc fill (very dark for body)
      ctx.fillStyle = "#050505";
      ctx.beginPath(); ctx.arc(cx, cy, R, 0, Math.PI * 2); ctx.fill();

      // Helpers: project a sphere-vector to 2D; horizon-clip a polyline by
      // linear-interpolating crossings where z = 0 so lines end exactly on
      // the sphere's silhouette instead of stopping at the last sampled
      // visible vertex (which is what makes the wireframe look jagged).
      function drawArc(samples) {
        if (samples.length < 2) return;
        ctx.beginPath();
        let started = false;
        let prev = null;
        for (let i = 0; i < samples.length; i++) {
          const cur = samples[i];
          const curVis = cur[2] >= 0;
          if (prev) {
            const prevVis = prev[2] >= 0;
            if (prevVis && curVis) {
              const p = project(cur, cx, cy, R);
              ctx.lineTo(p.x, p.y);
            } else if (prevVis && !curVis) {
              // crossing: prev visible, cur not — find z=0 between them
              const t = prev[2] / (prev[2] - cur[2]);
              const cross = [prev[0] + (cur[0]-prev[0])*t, prev[1] + (cur[1]-prev[1])*t, 0.0001];
              const p = project(cross, cx, cy, R);
              ctx.lineTo(p.x, p.y);
              started = false;
            } else if (!prevVis && curVis) {
              // crossing in the other direction
              const t = prev[2] / (prev[2] - cur[2]);
              const cross = [prev[0] + (cur[0]-prev[0])*t, prev[1] + (cur[1]-prev[1])*t, 0.0001];
              const p = project(cross, cx, cy, R);
              ctx.moveTo(p.x, p.y);
              const p2 = project(cur, cx, cy, R);
              ctx.lineTo(p2.x, p2.y);
              started = true;
            }
            // both invisible: skip
          } else if (curVis) {
            const p = project(cur, cx, cy, R);
            ctx.moveTo(p.x, p.y);
            started = true;
          }
          prev = cur;
        }
        ctx.stroke();
      }

      // 3) Parallels (latitude lines)
      const parallels = [-75,-60,-45,-30,-15,0,15,30,45,60,75];
      ctx.lineWidth = 1;
      parallels.forEach(lat => {
        const pts = [];
        for (let lng = -180; lng <= 180; lng += 3) {
          pts.push(latLngToVec3(lat, lng, yaw.current, pitch.current));
        }
        ctx.strokeStyle = lat === 0 ? "rgba(245,243,238,.26)" : "rgba(245,243,238,.10)";
        drawArc(pts);
      });

      // 4) Meridians (longitude lines)
      const meridians = [-150,-120,-90,-60,-30,0,30,60,90,120,150,180];
      meridians.forEach(lng => {
        const pts = [];
        for (let lat = -88; lat <= 88; lat += 2) {
          pts.push(latLngToVec3(lat, lng, yaw.current, pitch.current));
        }
        ctx.strokeStyle = lng === 0 ? "rgba(245,243,238,.26)" : "rgba(245,243,238,.10)";
        drawArc(pts);
      });

      // 5) Coastline polygons
      ctx.strokeStyle = "rgba(245,243,238,.62)";
      ctx.lineWidth = 1;
      COAST.forEach(poly => {
        // densify the coastline so projection looks smooth
        const dense = [];
        for (let i = 0; i < poly.length - 1; i++) {
          const a = poly[i], b = poly[i+1];
          const steps = 6;
          for (let s = 0; s < steps; s++) {
            const t = s / steps;
            dense.push([a[0] + (b[0]-a[0])*t, a[1] + (b[1]-a[1])*t]);
          }
        }
        dense.push(poly[poly.length-1]);
        const pts = dense.map(([lat,lng]) => latLngToVec3(lat, lng, yaw.current, pitch.current));
        drawArc(pts);
      });

      // 6) Sphere rim highlight (top-left)
      const grad = ctx.createRadialGradient(cx - R * 0.5, cy - R * 0.5, R * 0.1, cx, cy, R);
      grad.addColorStop(0, "rgba(245,243,238,.10)");
      grad.addColorStop(.6, "rgba(245,243,238,0)");
      ctx.fillStyle = grad;
      ctx.beginPath(); ctx.arc(cx, cy, R, 0, Math.PI * 2); ctx.fill();

      // Pins (rendered when the user hovers and the location is on the front hemisphere).
      const nextPins = [];
      LOCATIONS.forEach(loc => {
        const v = latLngToVec3(loc.lat, loc.lng, yaw.current, pitch.current);
        const front = v[2] > 0.05;
        if (!hovering.current || !front) return;
        const p = project(v, cx, cy, R);
        const t = performance.now() / 1000;
        const pulse = (Math.sin(t * 3 + (loc.primary ? 0 : 1.2)) * 0.5 + 0.5);
        ctx.strokeStyle = `rgba(232,222,200,${.55 + pulse * .35})`;
        ctx.lineWidth = 1;
        ctx.beginPath();
        ctx.arc(p.x, p.y, (loc.primary ? 14 : 11) + pulse * 4, 0, Math.PI * 2);
        ctx.stroke();
        const s = loc.primary ? 6 : 5;
        ctx.fillStyle = "rgba(232,222,200,1)";
        ctx.fillRect(p.x - s/2, p.y - s/2, s, s);
        ctx.strokeStyle = "rgba(0,0,0,1)";
        ctx.lineWidth = 1;
        ctx.strokeRect(p.x - s/2, p.y - s/2, s, s);
        const dir = loc.primary ? 1 : -1;
        const lx = p.x + dir * 18, ly = p.y - 22;
        ctx.strokeStyle = "rgba(232,222,200,.6)";
        ctx.beginPath();
        ctx.moveTo(p.x + dir * (s/2 + 1), p.y - s/2 - 1);
        ctx.lineTo(lx, ly);
        ctx.stroke();
        nextPins.push({ id: loc.id, mark: loc.mark, coord: loc.coord, primary: loc.primary, dir, x: lx, y: ly });
      });
      setPins(prev => {
        if (prev.length !== nextPins.length) return nextPins;
        for (let i = 0; i < nextPins.length; i++) {
          const a = prev[i], b = nextPins[i];
          if (!a || a.id !== b.id || Math.abs(a.x - b.x) > 0.5 || Math.abs(a.y - b.y) > 0.5) return nextPins;
        }
        return prev;
      });

      raf = requestAnimationFrame(tick);
    }
    raf = requestAnimationFrame(tick);
    return () => { cancelAnimationFrame(raf); ro.disconnect(); };
  }, []);

  return (
    <div className="hero-globe-wrap"
         onPointerEnter={() => { hovering.current = true; setPinVis(true); }}
         onPointerLeave={() => { hovering.current = false; setPinVis(false); }}>
      <canvas ref={ref} className="hero-globe" />
      {pins.map(pin => (
        <div key={pin.id}
             className={`hg-pin ${pinVis ? "visible" : ""} ${pin.primary ? "is-primary" : "is-secondary"} ${pin.dir < 0 ? "is-left" : "is-right"}`}
             style={{ left: pin.x + "px", top: pin.y + "px" }}>
          <span className="hg-pin-mark">{pin.mark}</span>
          <span className="hg-pin-coord">{pin.coord}</span>
        </div>
      ))}
      <div className="hg-caption">
        <span>The network</span>
      </div>
    </div>
  );
}

window.HeroGlobe = HeroGlobe;
