// hero.jsx — Hero with rotating globe (real continent outlines) + full footprint
const { useEffect, useRef, useState } = React;

// 12 featured sample locations (mirror the interactive map)
const GLOBE_PINS = [
  { city: "Tashkent",       country: "Uzbekistan",         lat: 41.3, lon:  69.2 },
  { city: "Manama",         country: "Bahrain",            lat: 26.2, lon:  50.6 },
  { city: "Pretoria",       country: "South Africa",       lat: -25.7,lon:  28.2 },
  { city: "Bogotá",         country: "Colombia",           lat:  4.7, lon: -74.1 },
  { city: "Oslo",           country: "Norway",             lat: 59.9, lon:  10.7 },
  { city: "Seoul",          country: "Republic of Korea",  lat: 37.5, lon: 127.0 },
  { city: "Suva",           country: "Fiji",               lat:-18.1, lon: 178.4 },
  { city: "Guatemala City", country: "Guatemala",          lat: 14.6, lon: -90.5 },
  { city: "Chișinău",       country: "Moldova",            lat: 47.0, lon:  28.9 },
  { city: "Hanoi",          country: "Vietnam",            lat: 21.0, lon: 105.8 },
  { city: "Nairobi",        country: "Kenya",              lat: -1.3, lon:  36.8 },
  { city: "Lobito",         country: "Angola",             lat:-12.3, lon:  13.5 },
];

// Full footprint = featured + every country from the shared location list.
const _FP = (typeof FOOTPRINT !== "undefined" ? FOOTPRINT : []);
const ALL_GLOBE = [
  ...GLOBE_PINS.map(p => ({ lat: p.lat, lon: p.lon, name: p.city, sub: p.country, featured: true })),
  ..._FP.map(f => ({ lat: f.lat, lon: f.lon, name: f.name, sub: "Capstone engagement", featured: false })),
];

function project(lat, lon, rot) {
  const φ = (lat * Math.PI) / 180;
  const λ = ((lon + rot) * Math.PI) / 180;
  return {
    x: Math.cos(φ) * Math.sin(λ),
    y: -Math.sin(φ),
    z: Math.cos(φ) * Math.cos(λ),
  };
}

function Hero({ heavy }) {
  const [rot, setRot] = useState(0);
  const [active, setActive] = useState(0);
  const [landRings, setLandRings] = useState([]);
  const [reach, setReach] = useState(0);
  const rafRef = useRef(0);
  const rotRef = useRef(0);

  // Rotation loop — throttled to ~30fps for smooth continent re-projection.
  useEffect(() => {
    let last = performance.now();
    let acc = 0;
    let r = 0;
    const tick = (t) => {
      const dt = t - last; last = t;
      r += dt * 0.011;
      rotRef.current = r;
      acc += dt;
      if (acc >= 33) { setRot(r); acc = 0; }
      rafRef.current = requestAnimationFrame(tick);
    };
    rafRef.current = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(rafRef.current);
  }, []);

  // Cycle the highlight through EVERY location once — no repeats until the whole
  // list has been shown, then it starts over. Only lands on locations currently
  // on the near face so the caption always names a visible dot.
  const usedRef = useRef(new Set());
  useEffect(() => {
    const pick = () => {
      const rr = rotRef.current;
      const front = [];
      for (let i = 0; i < ALL_GLOBE.length; i++) {
        const p = ALL_GLOBE[i];
        const z = Math.cos(p.lat * Math.PI / 180) * Math.cos((p.lon + rr) * Math.PI / 180);
        if (z > 0.32) front.push(i);
      }
      if (!front.length) return;
      // candidates = front-facing AND not yet highlighted this cycle
      let candidates = front.filter(i => !usedRef.current.has(i));
      if (!candidates.length) {
        // every location has had its turn → reset and start a new pass
        usedRef.current = new Set();
        candidates = front;
      }
      const choice = candidates[Math.floor(Math.random() * candidates.length)];
      usedRef.current.add(choice);
      setActive(choice);
    };
    pick();
    const id = setInterval(pick, 2100);
    return () => clearInterval(id);
  }, []);

  // Count-up for the "countries reached" caption.
  useEffect(() => {
    const total = ALL_GLOBE.length;
    const start = performance.now();
    const dur = heavy ? 1700 : 1200;
    let raf;
    const t = () => {
      const k = Math.min(1, (performance.now() - start) / dur);
      setReach(Math.round(total * (1 - Math.pow(1 - k, 3))));
      if (k < 1) raf = requestAnimationFrame(t);
    };
    raf = requestAnimationFrame(t);
    return () => cancelAnimationFrame(raf);
  }, [heavy]);

  // Load real coastlines once (same world-atlas source as the interactive map).
  useEffect(() => {
    let cancelled = false;
    (async () => {
      try {
        if (!window.topojson) return;
        const url = (window.__resources && window.__resources.worldAtlas)
          || "https://cdn.jsdelivr.net/npm/world-atlas@2.0.2/countries-110m.json";
        const topo = await fetch(url).then(r => r.json());
        const fc = window.topojson.feature(topo, topo.objects.countries);
        const rings = [];
        for (const f of fc.features) {
          if (!f.geometry || f.properties.name === "Antarctica") continue;
          const polys = f.geometry.type === "Polygon" ? [f.geometry.coordinates] : f.geometry.coordinates;
          for (const poly of polys) {
            for (const ring of poly) {
              if (ring.length < 5) continue;
              rings.push(ring);
            }
          }
        }
        if (!cancelled) setLandRings(rings);
      } catch (e) { /* wireframe-only fallback */ }
    })();
    return () => { cancelled = true; };
  }, []);

  const cx = 250, cy = 250, r = 220;

  // graticule
  const meridians = [];
  for (let lonOff = -90; lonOff <= 90; lonOff += 30) {
    const pts = [];
    for (let lat = -90; lat <= 90; lat += 6) {
      const p = project(lat, lonOff, rot);
      if (p.z > -0.001) pts.push(`${cx + p.x * r},${cy + p.y * r}`);
      else if (pts.length) { meridians.push(pts.join(" ")); pts.length = 0; }
    }
    if (pts.length) meridians.push(pts.join(" "));
  }
  const parallels = [];
  for (let lat = -60; lat <= 60; lat += 30) {
    const pts = [];
    for (let lon = -180; lon <= 180; lon += 4) {
      const p = project(lat, lon, rot);
      if (p.z > -0.001) pts.push(`${cx + p.x * r},${cy + p.y * r}`);
      else if (pts.length) { parallels.push(pts.join(" ")); pts.length = 0; }
    }
    if (pts.length) parallels.push(pts.join(" "));
  }

  // continents
  const landSegs = [];
  for (let ri = 0; ri < landRings.length; ri++) {
    const ring = landRings[ri];
    let cur = [];
    for (let i = 0; i < ring.length; i++) {
      const p = project(ring[i][1], ring[i][0], rot);
      if (p.z > 0.02) cur.push(`${(cx + p.x * r).toFixed(1)},${(cy + p.y * r).toFixed(1)}`);
      else if (cur.length) { if (cur.length > 1) landSegs.push(cur.join(" ")); cur = []; }
    }
    if (cur.length > 1) landSegs.push(cur.join(" "));
  }

  const a = ALL_GLOBE[active] || ALL_GLOBE[0];

  return (
    <section className="hero" id="top">
      <div className="container hero-grid">
        <div>
          <div className="hero-eyebrow reveal in">
            <span className="chev-ticks" aria-hidden="true"></span>
            Your signature graduate experience
          </div>

          <h1 className="display reveal in">
            Steps&nbsp;away
            <br />
            from <em>monumental</em>
            <br />
            change.
          </h1>

          <p className="lede reveal in">
            Across the last four cohorts, Elliott School master's students have shipped 165 real engagements to clients from State and DoD to the World Bank, USIP and the Pacific Islands Forum. Eight months. One client. The world's stakes.
          </p>

          <div className="hero-ctas reveal in">
            <a className="btn" href="#overview">
              How the year works <span className="chev">›</span>
            </a>
            <a className="btn ghost" href="#projects">
              Browse projects <span className="chev">›</span>
            </a>
          </div>
        </div>

        <div className="globe-col">
          <div className="globe-wrap">
            <svg className="globe-svg" viewBox="0 0 500 500" aria-hidden="true">
              <defs>
                <radialGradient id="g-sphere" cx="35%" cy="30%" r="80%">
                  <stop offset="0%" stopColor="#0A4868" />
                  <stop offset="65%" stopColor="#033C5A" />
                  <stop offset="100%" stopColor="#00223E" />
                </radialGradient>
                <radialGradient id="g-glow" cx="50%" cy="50%" r="50%">
                  <stop offset="80%" stopColor="rgba(0,117,200,0)" />
                  <stop offset="100%" stopColor="rgba(0,117,200,0.18)" />
                </radialGradient>
                <clipPath id="globe-clip">
                  <circle cx={cx} cy={cy} r={r} />
                </clipPath>
              </defs>

              <circle cx={cx} cy={cy} r={r + 18} fill="url(#g-glow)" />
              <circle cx={cx} cy={cy} r={r} fill="url(#g-sphere)" />

              <g clipPath="url(#globe-clip)">
                <g stroke="#D6BF91" strokeWidth="0.5" fill="none" opacity="0.16">
                  {meridians.map((p, i) => <polyline key={"m"+i} points={p} />)}
                  {parallels.map((p, i) => <polyline key={"p"+i} points={p} />)}
                </g>
                <g stroke="#D6BF91" strokeWidth="0.9" fill="none" opacity="0.8"
                   strokeLinejoin="round" strokeLinecap="round">
                  {landSegs.map((p, i) => <polyline key={"land"+i} points={p} />)}
                </g>
              </g>

              <circle cx={cx} cy={cy} r={r} fill="none" stroke="#D6BF91" strokeWidth="1.2" opacity="0.6" />

              {/* all 62 locations */}
              {ALL_GLOBE.map((pin, i) => {
                const p = project(pin.lat, pin.lon, rot);
                if (p.z < 0.04) return null;
                const px = cx + p.x * r;
                const py = cy + p.y * r;
                const isActive = i === active;
                const baseR = pin.featured ? 3.6 : 2.6;
                const op = (pin.featured ? 0.6 : 0.5) + p.z * 0.4;
                return (
                  <g key={i} opacity={isActive ? 1 : op}>
                    {isActive && (
                      <circle cx={px} cy={py} r={12} fill="none" stroke="#F6F1E8" strokeWidth="1.4">
                        <animate attributeName="r" from="5" to="26" dur="2s" repeatCount="indefinite" />
                        <animate attributeName="opacity" from="0.9" to="0" dur="2s" repeatCount="indefinite" />
                      </circle>
                    )}
                    <circle cx={px} cy={py} r={isActive ? 6 : baseR}
                      fill={isActive ? "#F6F1E8" : (pin.featured ? "#0075C8" : "#D6BF91")}
                      stroke={isActive ? "#00223E" : (pin.featured ? "#F6F1E8" : "none")}
                      strokeWidth={pin.featured || isActive ? 1 : 0} />
                  </g>
                );
              })}

              <g fill="#D6BF91" opacity="0.4" fontFamily="DM Sans" fontSize="9" fontWeight="600" letterSpacing="2">
                <text x={cx} y={20} textAnchor="middle">N</text>
                <text x={cx} y={490} textAnchor="middle">S</text>
                <text x={10} y={cy + 4}>W</text>
                <text x={486} y={cy + 4}>E</text>
              </g>
            </svg>
          </div>

          {/* caption sits BELOW the globe — never overlaps the sphere */}
          <div className="globe-cap">
            <div className="gc-active">
              <span className="gc-pulse" aria-hidden="true"></span>
              <span className="gc-name">{a.name}</span>
              <span className="gc-sub">{a.sub}</span>
            </div>
            <div className="gc-reach">
              <b>{reach}</b> countries reached
            </div>
          </div>
        </div>
      </div>
    </section>
  );
}

window.Hero = Hero;
