// globe-hero.jsx — Rotating world globe with trade-route arcs

const CANADA_ORIGIN = [-96, 56];

const TRADE_ROUTES = [
  { coords: [-66.9, 10.5],  label: 'Venezuela' },
  { coords: [-74.3,  4.7],  label: 'Colombia'  },
  { coords: [ 69.3, 30.4],  label: 'Pakistán'  },
  { coords: [104.2, 35.9],  label: 'China'     },
  { coords: [-102.5, 23.6], label: 'México'    },
  { coords: [ -3.7, 40.4],  label: 'España'    },
  { coords: [ 10.4, 51.2],  label: 'Alemania'  },
  { coords: [ 37.6, 55.7],  label: 'Rusia'     },
  { coords: [ 54.4, 24.5],  label: 'E.A.U.'    },
  { coords: [ -7.1, 31.8],  label: 'Marruecos' },
  { coords: [-51.9,-14.2],  label: 'Brasil'    },
  { coords: [ 28.0,  1.4],  label: 'África'    },
];

function WorldGlobeHero() {
  const wrapRef  = React.useRef(null);
  const canvasRef = React.useRef(null);

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

    const ctx = canvas.getContext('2d');
    const dpr = window.devicePixelRatio || 1;

    // ── sizing ──────────────────────────────────────────────────────────────
    let W = wrap.clientWidth || 900;
    const H = Math.min(520, window.innerHeight * 0.65);
    const resize = () => {
      W = wrap.clientWidth || 900;
      canvas.width  = W * dpr;
      canvas.height = H * dpr;
      canvas.style.width  = W + 'px';
      canvas.style.height = H + 'px';
      ctx.scale(dpr, dpr);
      projection.translate([W / 2, H / 2]).scale(Math.min(W, H) * 0.38);
    };

    // ── projection ──────────────────────────────────────────────────────────
    const projection = d3.geoOrthographic()
      .clipAngle(90)
      .translate([W / 2, H / 2])
      .scale(Math.min(W, H) * 0.38);

    const pathGen = d3.geoPath().projection(projection).context(ctx);
    resize();

    // ── state ───────────────────────────────────────────────────────────────
    let landFeatures = null;
    let allDots      = [];
    let rotLng       = -96;   // start centered on Americas
    let rotLat       = -20;
    let animT        = 0;

    // ── dot generation ──────────────────────────────────────────────────────
    const ptInPoly = ([x, y], ring) => {
      let inside = false;
      for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
        const [xi, yi] = ring[i], [xj, yj] = ring[j];
        if ((yi > y) !== (yj > y) && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi)
          inside = !inside;
      }
      return inside;
    };

    const ptInFeature = (pt, f) => {
      const g = f.geometry;
      if (g.type === 'Polygon') {
        if (!ptInPoly(pt, g.coordinates[0])) return false;
        for (let i = 1; i < g.coordinates.length; i++)
          if (ptInPoly(pt, g.coordinates[i])) return false;
        return true;
      }
      if (g.type === 'MultiPolygon') {
        for (const poly of g.coordinates) {
          if (ptInPoly(pt, poly[0])) {
            let hole = false;
            for (let i = 1; i < poly.length; i++)
              if (ptInPoly(pt, poly[i])) { hole = true; break; }
            if (!hole) return true;
          }
        }
      }
      return false;
    };

    const makeDots = (feature, step = 2.8) => {
      const dots = [];
      const [[mnLng, mnLat], [mxLng, mxLat]] = d3.geoBounds(feature);
      for (let lng = mnLng; lng <= mxLng; lng += step)
        for (let lat = mnLat; lat <= mxLat; lat += step)
          if (ptInFeature([lng, lat], feature)) dots.push([lng, lat]);
      return dots;
    };

    // ── arc drawing (uses D3 path so clipping is automatic) ─────────────────
    const makeArcGeoJSON = (from, to, progress) => {
      const interp = d3.geoInterpolate(from, to);
      const steps  = 80;
      const count  = Math.max(2, Math.round(steps * progress));
      const coords = [];
      for (let i = 0; i <= count; i++) coords.push(interp(i / steps));
      return { type: 'Feature', geometry: { type: 'LineString', coordinates: coords } };
    };

    // ── render ───────────────────────────────────────────────────────────────
    const render = () => {
      ctx.clearRect(0, 0, W, H);
      const R = projection.scale();

      // --- ocean sphere ---
      ctx.beginPath();
      ctx.arc(W / 2, H / 2, R, 0, 2 * Math.PI);
      ctx.fillStyle = '#0B0805';
      ctx.fill();

      // globe rim
      ctx.beginPath();
      ctx.arc(W / 2, H / 2, R, 0, 2 * Math.PI);
      ctx.strokeStyle = 'rgba(169,123,44,0.35)';
      ctx.lineWidth = 1.5;
      ctx.stroke();

      if (!landFeatures) return;

      // --- graticule ---
      ctx.beginPath();
      pathGen(d3.geoGraticule()());
      ctx.strokeStyle = 'rgba(245,237,224,0.05)';
      ctx.lineWidth = 0.5;
      ctx.stroke();

      // --- land fill ---
      ctx.beginPath();
      landFeatures.features.forEach(f => pathGen(f));
      ctx.fillStyle = 'rgba(107,63,29,0.18)';
      ctx.fill();

      // --- land outline ---
      ctx.beginPath();
      landFeatures.features.forEach(f => pathGen(f));
      ctx.strokeStyle = 'rgba(169,123,44,0.5)';
      ctx.lineWidth = 0.6;
      ctx.stroke();

      // --- land dots ---
      allDots.forEach(([lng, lat]) => {
        if (d3.geoDistance([lng, lat], [-rotLng, -rotLat]) > Math.PI / 2) return;
        const p = projection([lng, lat]);
        if (!p) return;
        ctx.beginPath();
        ctx.arc(p[0], p[1], 0.9, 0, 2 * Math.PI);
        ctx.fillStyle = 'rgba(169,123,44,0.55)';
        ctx.fill();
      });

      // --- connection arcs ---
      TRADE_ROUTES.forEach((route, i) => {
        // staggered phase: each arc reaches t=1 at a different time, then loops
        const cycle   = 6;            // seconds per full cycle
        const stagger = cycle / TRADE_ROUTES.length;
        const phase   = ((animT + i * stagger) % cycle) / cycle; // 0→1
        // 0→0.5: draw arc (progress 0→1); 0.5→1: arc stays full
        const progress = phase < 0.55 ? Math.min(1, phase / 0.45) : 1;
        const alpha    = phase < 0.85 ? 0.8 : 1 - (phase - 0.85) / 0.15; // fade out near end

        ctx.beginPath();
        pathGen(makeArcGeoJSON(CANADA_ORIGIN, route.coords, progress));
        ctx.strokeStyle = `rgba(212,169,74,${(alpha * 0.75).toFixed(2)})`;
        ctx.lineWidth   = 1.3;
        ctx.stroke();

        // glow pass
        ctx.beginPath();
        pathGen(makeArcGeoJSON(CANADA_ORIGIN, route.coords, progress));
        ctx.strokeStyle = `rgba(245,200,100,${(alpha * 0.2).toFixed(2)})`;
        ctx.lineWidth   = 3;
        ctx.stroke();
      });

      // --- destination dots + labels ---
      TRADE_ROUTES.forEach((route, i) => {
        const dist = d3.geoDistance(route.coords, [-rotLng, -rotLat]);
        if (dist > Math.PI / 2 * 0.95) return;
        const p = projection(route.coords);
        if (!p) return;

        const pulse = (Math.sin(animT * 2.5 + i) + 1) / 2;

        // outer pulse ring
        ctx.beginPath();
        ctx.arc(p[0], p[1], 4 + pulse * 5, 0, 2 * Math.PI);
        ctx.strokeStyle = 'rgba(212,169,74,0.35)';
        ctx.lineWidth   = 1;
        ctx.stroke();

        // inner dot
        ctx.beginPath();
        ctx.arc(p[0], p[1], 2.5, 0, 2 * Math.PI);
        ctx.fillStyle = '#D4A94A';
        ctx.fill();

        // label
        ctx.font      = '9px "JetBrains Mono", monospace';
        ctx.fillStyle = 'rgba(245,237,224,0.85)';
        ctx.fillText(route.label.toUpperCase(), p[0] + 7, p[1] + 3);
      });

      // --- Canada origin dot ---
      const dist0 = d3.geoDistance(CANADA_ORIGIN, [-rotLng, -rotLat]);
      if (dist0 < Math.PI / 2) {
        const p = projection(CANADA_ORIGIN);
        if (p) {
          const pulse = (Math.sin(animT * 3) + 1) / 2;
          ctx.beginPath();
          ctx.arc(p[0], p[1], 8 + pulse * 5, 0, 2 * Math.PI);
          ctx.strokeStyle = 'rgba(212,169,74,0.45)';
          ctx.lineWidth   = 1.5;
          ctx.stroke();

          ctx.beginPath();
          ctx.arc(p[0], p[1], 4, 0, 2 * Math.PI);
          ctx.fillStyle = '#D4A94A';
          ctx.fill();

          ctx.font      = 'bold 9px "JetBrains Mono", monospace';
          ctx.fillStyle = 'rgba(245,237,224,0.95)';
          ctx.fillText('CANADÁ', p[0] + 10, p[1] + 3);
        }
      }
    };

    // ── data load ────────────────────────────────────────────────────────────
    fetch('https://raw.githubusercontent.com/martynafford/natural-earth-geojson/refs/heads/master/110m/physical/ne_110m_land.json')
      .then(r => r.json())
      .then(data => {
        landFeatures = data;
        data.features.forEach(f => makeDots(f).forEach(d => allDots.push(d)));
      })
      .catch(e => console.warn('Globe: land data failed', e));

    // ── animation timer ──────────────────────────────────────────────────────
    const timer = d3.timer(elapsed => {
      animT   = elapsed / 1000;
      rotLng -= 0.06; // slow westward drift
      projection.rotate([rotLng, rotLat]);
      render();
    });

    // ── drag interaction ─────────────────────────────────────────────────────
    const onDown = e => {
      const sx = e.clientX, sy = e.clientY;
      const lr = rotLng, la = rotLat;
      const onMove = me => {
        rotLng = lr + (me.clientX - sx) * 0.35;
        rotLat = Math.max(-70, Math.min(70, la - (me.clientY - sy) * 0.35));
        projection.rotate([rotLng, rotLat]);
        render();
      };
      const onUp = () => {
        document.removeEventListener('mousemove', onMove);
        document.removeEventListener('mouseup', onUp);
      };
      document.addEventListener('mousemove', onMove);
      document.addEventListener('mouseup', onUp);
    };

    canvas.addEventListener('mousedown', onDown);

    return () => {
      timer.stop();
      canvas.removeEventListener('mousedown', onDown);
    };
  }, []);

  return (
    <div ref={wrapRef} style={{ position: 'relative', width: '100%', lineHeight: 0 }}>
      <canvas
        ref={canvasRef}
        role="img"
        aria-label="Interactive 3D globe"
        style={{ display: 'block', width: '100%', cursor: 'grab' }}
      />
      <div style={{
        position: 'absolute', bottom: 20, right: 24,
        fontFamily: 'var(--font-mono)', fontSize: 9,
        letterSpacing: '0.18em', textTransform: 'uppercase',
        color: 'rgba(169,123,44,0.55)',
      }}>
        Arrastra · Rota
      </div>
    </div>
  );
}

window.WorldGlobeHero = WorldGlobeHero;
