/* HeroOrb — A rotating 3D Earth with grad-cap pins floating up at random campus locations.
   Pure CSS 3D + SVG; no Three.js. The globe is a stack of latitude-rotated hemispheres
   built from SVG continents projected onto a sphere via CSS rotateY frames. */

const { useState, useEffect, useMemo, useRef } = React;

// Stylized continent silhouettes (simplified) drawn as SVG paths in equirectangular space (360°×180°)
// Reading: x=0..360 (lon -180..180 mapped), y=0..180 (lat 90..-90)
const CONTINENT_PATHS = [
  // North America
  "M40 30 Q55 25 70 35 L80 50 L72 70 L60 78 L48 70 L42 52 Z",
  // South America
  "M85 95 L95 90 L100 110 L92 135 L82 132 L80 110 Z",
  // Europe
  "M170 45 L195 42 L200 55 L188 65 L172 60 Z",
  // Africa
  "M180 75 L210 72 L218 100 L208 130 L192 132 L185 105 Z",
  // Asia
  "M210 35 L290 38 L298 60 L280 78 L240 75 L215 60 Z",
  // India
  "M250 75 L268 75 L266 95 L255 100 L248 88 Z",
  // Australia
  "M290 115 L320 112 L325 130 L310 138 L292 130 Z",
  // Greenland
  "M120 18 L140 18 L142 32 L128 36 L120 28 Z",
  // UK
  "M158 42 L168 40 L168 50 L160 52 Z",
  // Japan
  "M310 55 L320 50 L322 65 L314 68 Z",
  // Madagascar
  "M222 110 L228 110 L228 125 L222 125 Z",
];

// Cap pin sites (lat, lon, name) — picked to span the globe
const CAMPUS_SITES = [
  { lat: 42.4,  lon: -71.1, name: "Cambridge" },     // Harvard / MIT
  { lat: 37.4,  lon: -122.2, name: "Stanford" },
  { lat: 40.8,  lon: -74.0, name: "Princeton/Columbia" },
  { lat: 51.75, lon: -1.26, name: "Oxford" },
  { lat: 52.20, lon: 0.12,  name: "Cambridge UK" },
  { lat: 48.85, lon: 2.34,  name: "Paris" },
  { lat: 35.71, lon: 139.76, name: "Tokyo" },
  { lat: 22.30, lon: 114.17, name: "Hong Kong" },
  { lat: 1.30,  lon: 103.85, name: "Singapore" },
  { lat: 28.61, lon: 77.20, name: "Delhi" },
  { lat: -33.86, lon: 151.21, name: "Sydney" },
  { lat: 43.66, lon: -79.39, name: "Toronto" },
];

// Project (lat, lon, rotation) → 2D point on a circle of radius R, returning back-face flag.
// Sphere is rendered as an SVG circle; we compute x,y,z relative to the rotation, project x/z to 2D.
const project = (lat, lon, rotY, R) => {
  const phi = (lat * Math.PI) / 180;
  const theta = ((lon + rotY) * Math.PI) / 180;
  const x = R * Math.cos(phi) * Math.sin(theta);
  const y = -R * Math.sin(phi);
  const z = R * Math.cos(phi) * Math.cos(theta);
  return { x, y, z, back: z < 0 };
};

const GradCap = ({ size = 18, accent }) => (
  <svg viewBox="-12 -10 24 20" width={size} height={size} style={{ display: "block", overflow: "visible" }}>
    {/* Mortarboard (square top) */}
    <polygon points="-10,-2 0,-7 10,-2 0,3" fill={accent} stroke="#ffffff" strokeWidth="0.6" />
    {/* Cap base */}
    <path d="M -7 0 L -7 4 Q 0 7 7 4 L 7 0" fill={accent} stroke="#ffffff" strokeWidth="0.6" />
    {/* Tassel */}
    <line x1="0" y1="-2" x2="6" y2="6" stroke="#ffffff" strokeWidth="0.6" />
    <circle cx="6" cy="6" r="1.4" fill="#ffffff" />
    {/* Button */}
    <circle cx="0" cy="-2" r="0.9" fill="#ffffff" />
  </svg>
);

const HeroOrb = ({ scroll = 0, mouse = { x: 0, y: 0 }, accent }) => {
  const [t, setT] = useState(0);
  useEffect(() => {
    let raf, start = performance.now();
    const loop = () => { setT((performance.now() - start) / 1000); raf = requestAnimationFrame(loop); };
    raf = requestAnimationFrame(loop);
    return () => cancelAnimationFrame(raf);
  }, []);

  // Rotation
  const rotY = (t * 8) + mouse.x * 14;        // continuous earth spin + parallax
  const tiltX = -18 + mouse.y * -6;            // axial tilt
  const orbY = scroll * -120;
  const orbScale = 1 - Math.min(scroll * 0.25, 0.25);
  const orbOpacity = 1 - Math.min(scroll * 1.4, 1);

  // Stars
  const stars = useMemo(() => Array.from({ length: 90 }, () => ({
    x: Math.random() * 100, y: Math.random() * 100,
    s: Math.random() * 1.4 + 0.3, d: Math.random() * 4,
  })), []);

  // Globe sizing
  const R = 220;        // sphere radius in SVG units
  const VIEW = 560;     // svg viewbox

  // Decide which 4 sites currently "pop" their caps based on time
  const visibleCaps = useMemo(() => {
    const popPeriod = 2.4;
    const cycleIdx = Math.floor(t / popPeriod);
    // Stable selection from t-cycle
    const seed = (n) => ((cycleIdx * 9301 + n * 49297) % 233280) / 233280;
    const indices = CAMPUS_SITES.map((_, i) => i)
      .sort((a, b) => seed(a) - seed(b))
      .slice(0, 5);
    const phase = (t % popPeriod) / popPeriod; // 0..1
    return indices.map((i, k) => ({
      ...CAMPUS_SITES[i],
      pop: Math.max(0, Math.sin(Math.min(1, phase * 1.3) * Math.PI)) * (1 - k * 0.05),
    }));
  }, [Math.floor(t * 4)]);

  return (
    <div aria-hidden="true" style={{
      position: "absolute", inset: 0,
      display: "flex", alignItems: "center", justifyContent: "center",
      pointerEvents: "none",
      transform: `translateY(${orbY}px) scale(${orbScale})`,
      opacity: orbOpacity,
      transition: "opacity 200ms linear",
    }}>
      {/* Star field */}
      <div style={{ position: "absolute", inset: 0, overflow: "hidden" }}>
        {stars.map((s, i) => (
          <span key={i} style={{
            position: "absolute",
            left: `${s.x}%`, top: `${s.y}%`,
            width: `${s.s}px`, height: `${s.s}px`,
            background: "rgba(244,243,238,0.85)",
            borderRadius: "50%",
            boxShadow: "0 0 6px rgba(244,243,238,0.6)",
            opacity: 0.35 + 0.55 * Math.abs(Math.sin(t * 0.7 + s.d)),
          }} />
        ))}
      </div>

      {/* Outer glow halo */}
      <div style={{
        position: "absolute",
        width: "min(78vmin, 720px)",
        height: "min(78vmin, 720px)",
        borderRadius: "50%",
        background: `radial-gradient(circle at 50% 50%, ${accent}33 0%, ${accent}11 30%, transparent 60%)`,
        filter: "blur(24px)",
      }} />

      {/* Tilted globe wrapper — applies the axial tilt; SVG handles rotation */}
      <div style={{
        position: "relative",
        width: "min(60vmin, 560px)", height: "min(60vmin, 560px)",
        transform: `rotateZ(${tiltX * 0.6}deg)`,
        filter: "drop-shadow(0 30px 80px rgba(0,0,0,0.6))",
      }}>
        <svg viewBox={`${-VIEW/2} ${-VIEW/2} ${VIEW} ${VIEW}`} style={{ width: "100%", height: "100%", overflow: "visible" }}>
          <defs>
            {/* Ocean radial — shaded sphere look */}
            <radialGradient id="ocean" cx="35%" cy="30%" r="75%">
              <stop offset="0%" stopColor="#1f4a7a" />
              <stop offset="40%" stopColor="#12325a" />
              <stop offset="80%" stopColor="#08182e" />
              <stop offset="100%" stopColor="#04060a" />
            </radialGradient>
            <radialGradient id="atmosphere" cx="50%" cy="50%" r="55%">
              <stop offset="80%" stopColor={accent} stopOpacity="0" />
              <stop offset="95%" stopColor={accent} stopOpacity="0.45" />
              <stop offset="100%" stopColor={accent} stopOpacity="0" />
            </radialGradient>
            <radialGradient id="terminator" cx="70%" cy="60%" r="80%">
              <stop offset="0%" stopColor="rgba(0,0,0,0)" />
              <stop offset="60%" stopColor="rgba(0,0,0,0)" />
              <stop offset="100%" stopColor="rgba(0,0,0,0.85)" />
            </radialGradient>
            <radialGradient id="specular" cx="30%" cy="22%" r="22%">
              <stop offset="0%" stopColor="rgba(244,243,238,0.55)" />
              <stop offset="100%" stopColor="rgba(244,243,238,0)" />
            </radialGradient>
            <clipPath id="globeClip">
              <circle cx="0" cy="0" r={R} />
            </clipPath>
          </defs>

          {/* Atmosphere ring */}
          <circle cx="0" cy="0" r={R * 1.18} fill="url(#atmosphere)" />

          {/* Ocean sphere */}
          <circle cx="0" cy="0" r={R} fill="url(#ocean)" />

          {/* Lat/lon graticule, projected */}
          <g clipPath="url(#globeClip)" opacity="0.18">
            {/* Latitude rings */}
            {[-60, -30, 0, 30, 60].map((lat, i) => {
              const ry = R * Math.cos(lat * Math.PI / 180);
              const yOff = -R * Math.sin(lat * Math.PI / 180);
              return <ellipse key={i} cx="0" cy={yOff} rx={R} ry={Math.max(2, ry * 0.18)} fill="none" stroke="#7fb1e6" strokeWidth="0.6" />;
            })}
            {/* Longitude meridians — eight, animated by rotation */}
            {[0, 22.5, 45, 67.5, 90, 112.5, 135, 157.5].map((lon, i) => {
              const a = ((lon + rotY) * Math.PI) / 180;
              const rx = Math.abs(R * Math.sin(a));
              const opacity = Math.max(0.15, Math.cos(a));
              return <ellipse key={i} cx="0" cy="0" rx={rx} ry={R} fill="none" stroke="#7fb1e6" strokeOpacity={opacity} strokeWidth="0.6" />;
            })}
          </g>

          {/* Continents — orthographic projection, hide back-face polygons by per-vertex z */}
          <g clipPath="url(#globeClip)">
            {CONTINENT_PATHS.map((path, ci) => {
              // Convert path coordinates (equirectangular 0..360 / 0..180) into projected polygons.
              // Quick parser: extract numeric pairs from the path string.
              const nums = path.match(/-?\d+(\.\d+)?/g).map(Number);
              const points = [];
              for (let i = 0; i < nums.length; i += 2) {
                const lon = nums[i] - 180;        // x: 0..360 → -180..180
                const lat = 90 - nums[i + 1];     // y: 0..180 → 90..-90
                const p = project(lat, lon, rotY, R);
                points.push(p);
              }
              // If majority of vertices are on back side, skip
              const backCount = points.filter(p => p.back).length;
              if (backCount > points.length * 0.55) return null;

              // Build polygon string from front vertices (clip to front by simple z>0 mask)
              const poly = points.map(p => `${p.x.toFixed(1)},${p.y.toFixed(1)}`).join(" ");
              // Shade by average z to fake lambert
              const avgZ = points.reduce((s, p) => s + p.z, 0) / points.length;
              const lit = Math.max(0.25, avgZ / R);
              const fill = `rgba(${Math.round(70 + 80 * lit)}, ${Math.round(140 + 70 * lit)}, ${Math.round(110 + 60 * lit)}, ${0.65 + 0.3 * lit})`;
              return (
                <polygon key={ci} points={poly} fill={fill}
                  stroke="rgba(244,243,238,0.20)" strokeWidth="0.5" strokeLinejoin="round" />
              );
            })}
          </g>

          {/* Terminator shading (night side) */}
          <circle cx="0" cy="0" r={R} fill="url(#terminator)" />

          {/* Specular highlight */}
          <ellipse cx={-R * 0.35} cy={-R * 0.45} rx={R * 0.32} ry={R * 0.18} fill="url(#specular)" />

          {/* Rim light */}
          <circle cx="0" cy="0" r={R} fill="none" stroke={accent} strokeWidth="1.2" strokeOpacity="0.4" />

          {/* Campus pins */}
          {visibleCaps.map((c, i) => {
            const p = project(c.lat, c.lon, rotY, R);
            if (p.back) return null;
            const popY = -28 * c.pop;       // float upward
            const opacity = c.pop;
            const capSize = 22;
            return (
              <g key={`${c.name}-${i}`} transform={`translate(${p.x}, ${p.y})`} opacity={opacity}>
                {/* Pin base */}
                <circle r="3.5" fill={accent} stroke="#ffffff" strokeWidth="1.2" />
                {/* Halo ring */}
                <circle r={3.5 + 8 * c.pop} fill="none" stroke={accent} strokeOpacity={0.5 * (1 - c.pop)} strokeWidth="1" />
                {/* Tether line up */}
                <line x1="0" y1="0" x2="0" y2={popY + 10} stroke={accent} strokeOpacity="0.6" strokeWidth="0.8" strokeDasharray="2 2" />
                {/* Cap */}
                <g transform={`translate(${0}, ${popY})`}>
                  <foreignObject x={-capSize/2} y={-capSize/2 - 2} width={capSize} height={capSize}>
                    <div xmlns="http://www.w3.org/1999/xhtml" style={{ width: "100%", height: "100%", display: "flex", alignItems: "center", justifyContent: "center", filter: `drop-shadow(0 4px 8px ${accent}88)` }}>
                      <GradCap size={capSize} accent={accent} />
                    </div>
                  </foreignObject>
                </g>
              </g>
            );
          })}
        </svg>

        {/* Soft floor shadow */}
        <div style={{
          position: "absolute",
          left: "50%", bottom: "-10%",
          width: "70%", height: "12%",
          transform: "translateX(-50%)",
          background: `radial-gradient(ellipse at 50% 0%, rgba(0,0,0,0.55) 0%, transparent 70%)`,
          filter: "blur(14px)",
        }} />
      </div>

      {/* Outer orbit ring — a satellite arc */}
      <div style={{
        position: "absolute",
        width: "min(82vmin, 760px)", height: "min(82vmin, 760px)",
        borderRadius: "50%",
        border: "1px dashed rgba(244,243,238,0.10)",
        transform: `rotate(${(t * 6) % 360}deg)`,
      }}>
        <div style={{
          position: "absolute", left: "50%", top: 0,
          width: 8, height: 8, marginLeft: -4,
          borderRadius: "50%",
          background: accent,
          boxShadow: `0 0 16px ${accent}`,
        }} />
      </div>
    </div>
  );
};

window.HeroOrb = HeroOrb;
