// planet.jsx — Earth with NASA Blue Marble texture, moons + space station orbiting
// in DIFFERENT inclined planes. Objects pass behind the planet (occluded) on the
// far half of their orbit, and in front on the near half.

function Planet({ scrollProgress = 0 }) {
  const scale = 1 - Math.min(scrollProgress * 0.4, 0.4);
  const opacity = 1 - Math.min(scrollProgress * 1.4, 0.85);

  const CX = 360, CY = 360, R = 180;

  // Texture: 2048x1024. Render at 720x360 (2:1) inside the planet circle.
  const TEX_W = 720, TEX_H = 360;
  const TEX_TOP = CY - TEX_H / 2;

  // Ring (the visible band around the planet)
  const ringTilt = 18;
  const ringRx = 320, ringRy = 80;

  // Three orbital tracks. Each has its own (rx, ry, tilt) — so they're DIFFERENT planes.
  // Convention: orbit ellipse defined around (0,0), then rotated by `tilt` deg.
  // The "near" half of the orbit (visible in front of the planet) is the BOTTOM half
  // of the un-tilted ellipse (y > 0 in object coords, which after the tilt becomes
  // the half closer to the viewer). The "far" half is the TOP (y < 0), which is occluded.
  //
  // For each orbit we generate:
  //   • a back path (top half, drawn UNDER the planet body) — gets occluded
  //   • a front path (bottom half, drawn OVER the planet body)
  // Each path runs from one edge of the orbit to the other, looping continuously
  // by chaining a back-segment animation and a front-segment animation back to back.
  //
  // We achieve this with motion via SVG <animateMotion> on the FULL ellipse, but
  // we render the SAME object twice: once before the planet (back layer) and once
  // after (front layer). Each instance is clipped so it only shows on its half of
  // the orbit — using a clipPath that's a rotated rectangle covering exactly that half.

  const orbits = [
    {
      key: 'station',
      rx: ringRx, ry: ringRy, tilt: ringTilt,    // SAME plane as the ring
      duration: 22, phase: 0.35,                  // different start than ring
      reverse: false,
    },
    {
      key: 'moon-a',
      rx: 250, ry: 70, tilt: -28,                 // different plane
      duration: 36, phase: 0.0,
      reverse: false,
    },
    {
      key: 'moon-b',
      rx: 305, ry: 35, tilt: 42,                  // yet another plane (steeper tilt, flatter orbit)
      duration: 28, phase: 0.6,
      reverse: true,
    },
  ];

  // Build a full-ellipse path centered at (CX,CY) starting at the right vertex.
  const ellipsePath = (rx, ry) =>
    `M ${CX + rx},${CY} A ${rx},${ry} 0 0 1 ${CX - rx},${CY} A ${rx},${ry} 0 0 1 ${CX + rx},${CY}`;

  return (
    <div className="planet-stage" style={{
      transform: `scale(${scale})`,
      opacity,
      transition: 'opacity 0.1s linear'
    }}>
      <div className="planet-wrap">
        <svg viewBox="0 0 720 720" width="100%" height="100%">
          <defs>
            <radialGradient id="planet-glow" cx="50%" cy="50%" r="50%">
              <stop offset="60%" stopColor="rgba(120, 180, 255, 0)" />
              <stop offset="85%" stopColor="rgba(120, 180, 255, 0.30)" />
              <stop offset="100%" stopColor="rgba(120, 180, 255, 0)" />
            </radialGradient>
            <linearGradient id="planet-ring1" x1="0" y1="0" x2="1" y2="0">
              <stop offset="0%" stopColor="oklch(0.6 0.18 268)" stopOpacity="0" />
              <stop offset="20%" stopColor="oklch(0.85 0.16 268)" stopOpacity="0.95" />
              <stop offset="50%" stopColor="oklch(0.95 0.10 268)" stopOpacity="1" />
              <stop offset="80%" stopColor="oklch(0.78 0.14 195)" stopOpacity="0.95" />
              <stop offset="100%" stopColor="oklch(0.6 0.18 195)" stopOpacity="0" />
            </linearGradient>
            <radialGradient id="terminator" cx="32%" cy="30%" r="85%">
              <stop offset="40%" stopColor="rgba(0,0,0,0)" />
              <stop offset="78%" stopColor="rgba(0,0,0,0.45)" />
              <stop offset="100%" stopColor="rgba(0,0,0,0.78)" />
            </radialGradient>
            <radialGradient id="atmo" cx="50%" cy="50%" r="50%">
              <stop offset="88%" stopColor="rgba(140, 200, 255, 0)" />
              <stop offset="97%" stopColor="rgba(140, 200, 255, 0.55)" />
              <stop offset="100%" stopColor="rgba(180, 220, 255, 0.85)" />
            </radialGradient>
            <radialGradient id="specular" cx="50%" cy="50%" r="50%">
              <stop offset="0%" stopColor="rgba(220, 240, 255, 0.35)" />
              <stop offset="100%" stopColor="rgba(220, 240, 255, 0)" />
            </radialGradient>
            <clipPath id="planet-clip">
              <circle cx={CX} cy={CY} r={R} />
            </clipPath>
            {/* "Outside the earth disc" mask — for FRONT instances of orbital bodies.
                White everywhere, black inside the planet circle, so the body is hidden
                wherever it overlaps the earth (the back instance, drawn earlier and
                covered by the earth body, takes over there visually — but actually we
                rely on z-order alone for the back side, so the front instance is just
                clipped out where the planet sits). */}
            <mask id="outside-earth" maskUnits="userSpaceOnUse" x="0" y="0" width="720" height="720">
              <rect x="0" y="0" width="720" height="720" fill="white" />
              <circle cx={CX} cy={CY} r={R - 2} fill="black" />
            </mask>

            {orbits.map(o => (
              <path key={o.key} id={`orbit-path-${o.key}`} d={ellipsePath(o.rx, o.ry)} />
            ))}

            {/* Reusable orbital body shapes */}
            <g id="moon-a-shape">
              <circle r="16" fill="rgba(212,216,221,0.18)" />
              <circle r="7" fill="#d4d8dd" />
              <circle cx="2" cy="-1" r="2" fill="#9aa0a8" opacity="0.6" />
              <circle cx="-2" cy="2" r="1.2" fill="#9aa0a8" opacity="0.5" />
            </g>
            <g id="moon-b-shape">
              <circle r="10" fill="rgba(232,213,176,0.18)" />
              <circle r="4.5" fill="#e8d5b0" />
              <circle cx="1" cy="-1" r="1" fill="#a89878" opacity="0.6" />
            </g>
            <g id="station-shape">
              <ellipse cx="-14" cy="0" rx="18" ry="3" fill="rgba(180,220,255,0.35)" />
              <rect x="-10" y="-2" width="20" height="4" fill="#cdd2d8" stroke="#6a7280" strokeWidth="0.4" />
              <rect x="-22" y="-7" width="11" height="14" fill="#1a3a6a" stroke="#3a5a8a" strokeWidth="0.4" />
              <line x1="-22" y1="-3.5" x2="-11" y2="-3.5" stroke="#3a5a8a" strokeWidth="0.3" />
              <line x1="-22" y1="0" x2="-11" y2="0" stroke="#3a5a8a" strokeWidth="0.3" />
              <line x1="-22" y1="3.5" x2="-11" y2="3.5" stroke="#3a5a8a" strokeWidth="0.3" />
              <line x1="-16.5" y1="-7" x2="-16.5" y2="7" stroke="#3a5a8a" strokeWidth="0.3" />
              <rect x="11" y="-7" width="11" height="14" fill="#1a3a6a" stroke="#3a5a8a" strokeWidth="0.4" />
              <line x1="11" y1="-3.5" x2="22" y2="-3.5" stroke="#3a5a8a" strokeWidth="0.3" />
              <line x1="11" y1="0" x2="22" y2="0" stroke="#3a5a8a" strokeWidth="0.3" />
              <line x1="11" y1="3.5" x2="22" y2="3.5" stroke="#3a5a8a" strokeWidth="0.3" />
              <line x1="16.5" y1="-7" x2="16.5" y2="7" stroke="#3a5a8a" strokeWidth="0.3" />
              <rect x="-5" y="-4" width="10" height="8" rx="1" fill="#e8ecef" stroke="#8a9098" strokeWidth="0.4" />
              <circle cx="0" cy="0" r="1.5" fill="#3a5a8a" />
              <line x1="0" y1="-4" x2="0" y2="-8" stroke="#cdd2d8" strokeWidth="0.6" />
              <circle cx="0" cy="-8.5" r="0.8" fill="#ff6a6a" />
            </g>
          </defs>

          {/* === BACKGROUND LAYERS (behind planet) === */}

          {/* Outer aura */}
          <circle cx={CX} cy={CY} r="340" fill="url(#planet-glow)" />

          {/* Back half of ring */}
          <g className="ring-spin-back">
            <g transform={`rotate(${ringTilt} ${CX} ${CY})`}>
              <path
                d={`M ${CX - ringRx},${CY} A ${ringRx},${ringRy} 0 0 1 ${CX + ringRx},${CY}`}
                stroke="url(#planet-ring1)" strokeWidth="3" fill="none"
                opacity="0.9" />
            </g>
          </g>

          {/* Orbital bodies — BACK instance (drawn before planet, occluded by it).
              Each body is rendered TWICE: a back copy (this one) and a front copy
              (drawn after the planet). Synchronized opacity animations make each
              copy visible only during its half of the orbit, so the body smoothly
              passes BEHIND the planet on the back half and IN FRONT on the front
              half — true 3D depth despite SVG's flat z-order. */}
          {orbits.map(o => (
            <g key={`back-${o.key}`}>
              <OrbitingBody orbit={o} layer="back" />
            </g>
          ))}

          {/* === EARTH BODY === */}
          <g>
            <g clipPath="url(#planet-clip)">
              <g className="earth-spin">
                <image href="assets/earth_4k.jpg"
                  x={CX - R} y={TEX_TOP} width={TEX_W} height={TEX_H}
                  preserveAspectRatio="none" />
                <image href="assets/earth_4k.jpg"
                  x={CX - R + TEX_W} y={TEX_TOP} width={TEX_W} height={TEX_H}
                  preserveAspectRatio="none" />
              </g>
              <ellipse cx={CX - 70} cy={CY - 70} rx="70" ry="50" fill="url(#specular)" />
              <circle cx={CX} cy={CY} r={R} fill="url(#terminator)" />
            </g>
            <circle cx={CX} cy={CY} r={R + 2} fill="url(#atmo)" />
          </g>

          {/* === FOREGROUND LAYERS (in front of planet) === */}

          {/* Front half of ring */}
          <g className="ring-spin-front">
            <g transform={`rotate(${ringTilt} ${CX} ${CY})`}>
              <path
                d={`M ${CX - ringRx},${CY} A ${ringRx},${ringRy} 0 0 0 ${CX + ringRx},${CY}`}
                stroke="url(#planet-ring1)" strokeWidth="3.5" fill="none"
                opacity="1" />
            </g>
          </g>

          {/* Orbital bodies — FRONT instance (drawn after planet, on top of it).
              Visible only during the front half of the orbit; sibling back instance
              handles the rear half. No mask — when a body is on the front half AND
              over the disc, it should pass IN FRONT of the planet. */}
          {orbits.map(o => (
            <g key={`front-${o.key}`}>
              <OrbitingBody orbit={o} layer="front" />
            </g>
          ))}
        </svg>
      </div>
    </div>
  );
}

// One orbital body — uses <animateMotion> on a shared orbit path.
// Both layer instances ('back' / 'front') of the same orbit run the SAME animation
// (same path, duration, begin time) so they're frame-locked. Each layer's clipPath
// shows only the appropriate half. Together they look like a single object circling
// in 3D, occluded by the planet on the far side.
function OrbitingBody({ orbit, layer }) {
  const { key, duration, phase, reverse, tilt } = orbit;
  const dur = `${duration}s`;
  // Use a NEGATIVE begin to start the animation already advanced by `phase * duration`.
  // Both layers share the same begin so their positions match exactly.
  const begin = `${-phase * duration}s`;

  // Reverse direction → use keyPoints/keyTimes to go around the path backwards.
  const motionProps = reverse
    ? { keyPoints: '1;0', keyTimes: '0;1', calcMode: 'linear' }
    : {};

  // Depth gating — the body needs to be visible only on the half of the
  // orbit assigned to this layer. The path's half-cycle boundary (t=0.5)
  // is the body crossing the planet's silhouette. With a tiny crossfade
  // around that boundary we avoid a pop when layers swap. For a forward
  // ellipse traversal (CCW from the right vertex), upper arc = [0,0.5],
  // lower arc = [0.5,1]. With tilt the upper/lower map to back/front in
  // the rotated frame; that's still a clean depth split. When the orbit
  // is `reverse: true` we flip the visibility mapping so back stays back.
  const FADE = 0.04;        // 4% of period crossfade — ~1s on a 22s orbit
  const buildVisibility = (visibleFirstHalf) => {
    // first-half visible: 1 → 1 → 0 → 0 → 1 over [0, 0.5−f, 0.5+f, 1−f, 1]
    // second-half visible: invert.
    if (visibleFirstHalf) {
      return {
        values:   '1;1;0;0;1',
        keyTimes: `0;${0.5 - FADE};${0.5 + FADE};${1 - FADE};1`,
      };
    }
    return {
      values:   '0;0;1;1;0',
      keyTimes: `0;${0.5 - FADE};${0.5 + FADE};${1 - FADE};1`,
    };
  };
  // Without `reverse`, t=0 is at the right vertex moving up first, so the
  // first half is the "back" arc. With `reverse`, the body moves DOWN
  // first → first half is the "front" arc.
  const backIsFirstHalf = !reverse;
  const visibleFirstHalf = layer === 'back' ? backIsFirstHalf : !backIsFirstHalf;
  const vis = buildVisibility(visibleFirstHalf);

  // Tilt the orbital plane around the planet center so each orbit traces
  // a different 3D plane. Without this rotate, every ellipse lay flat on
  // the screen — adding it makes ISS / moons sweep across distinct
  // inclinations the way real satellites do.
  return (
    <g transform={`rotate(${tilt || 0} 360 360)`}>
      <use href={`#${key}-shape`} opacity="0">
        <animateMotion
          dur={dur}
          repeatCount="indefinite"
          rotate="0"
          begin={begin}
          {...motionProps}
        >
          <mpath href={`#orbit-path-${key}`} />
        </animateMotion>
        <animate
          attributeName="opacity"
          dur={dur}
          repeatCount="indefinite"
          begin={begin}
          values={vis.values}
          keyTimes={vis.keyTimes}
          calcMode="linear"
        />
      </use>
    </g>
  );
}

window.Planet = Planet;
