// space.jsx — Trek-style viewscreen backdrop for PLUR demo video.
//
// Design goal: the entire stage IS the bridge viewscreen. Space is always
// visible; terminals and callouts float as HUD panels over it. Warps are
// native star behavior (existing stars elongate and punch forward) rather
// than an overlaid effect.
//
// Components:
//   <Viewscreen>       — deep-space backdrop: gradient, nebulae, stars, warp
//   <WarpTransition>   — publishes a warp-active window so <Viewscreen> stretches
//                        its stars. Renders no visuals of its own — just state.
//   <GasGiant>         — optional slow-rotating planet for accent
//
// All components read Stage time via useTimeline().

// ─── Deterministic RNG ─────────────────────────────────────────────────────
function mulberry32(seed) {
  let a = seed >>> 0;
  return function() {
    a = (a + 0x6D2B79F5) >>> 0;
    let t = a;
    t = Math.imul(t ^ (t >>> 15), t | 1);
    t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
    return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
  };
}

// ─── Shared warp state ─────────────────────────────────────────────────────
// WarpTransition components register their windows here; Viewscreen reads them.
const __warpWindows = [];
function registerWarp(w) {
  __warpWindows.push(w);
  return () => {
    const i = __warpWindows.indexOf(w);
    if (i >= 0) __warpWindows.splice(i, 1);
  };
}
// Returns { power: 0..1, direction: 'forward' } for a given time.
function warpAt(time) {
  let power = 0;
  for (const w of __warpWindows) {
    if (time < w.start || time > w.end) continue;
    const t = (time - w.start) / (w.end - w.start);
    // Exponential spool-up → peak → smooth drop.
    // Feels like actually jumping to warp: slow lean, then SNAP, then decelerate.
    let p;
    if (t < 0.45) {
      // Exponential acceleration — eased quint for that "leaning forward" feel
      const a = t / 0.45;
      p = a * a * a; // cubic → exponential feel
    } else if (t > 0.7) {
      // Smooth decel after peak
      const a = (t - 0.7) / 0.3;
      p = 1 - a * a; // quadratic ease-out
    } else {
      p = 1;
    }
    power = Math.max(power, p * (w.intensity || 1));
  }
  return power;
}

// ─── Viewscreen — the ALWAYS-ON space backdrop ─────────────────────────────
function Viewscreen({ density = 1.0, opacity = 1.0, seed = 42 }) {
  const { time } = useTimeline();

  const stars = React.useMemo(() => {
    const rng = mulberry32(seed);
    const layers = [
      // Far: tiny, many, slow
      { count: Math.floor(180 * density), size: [0.7, 1.3], speed: 0.4, opacity: [0.3, 0.55] },
      // Mid: medium, some twinkle
      { count: Math.floor(90  * density), size: [1.3, 2.2], speed: 1.1, opacity: [0.55, 0.85] },
      // Near: bright, fast (these streak most dramatically in warp)
      { count: Math.floor(40  * density), size: [2.2, 3.6], speed: 2.6, opacity: [0.8, 1.0]  },
    ];
    const out = [];
    layers.forEach((L, li) => {
      for (let i = 0; i < L.count; i++) {
        // Distribute stars around a center-out polar field so warp feels radial
        const angle = rng() * Math.PI * 2;
        const radius = rng() * 1300; // distance from center at t=0
        out.push({
          layer: li,
          angle,
          baseRadius: radius,
          s: L.size[0] + rng() * (L.size[1] - L.size[0]),
          o: L.opacity[0] + rng() * (L.opacity[1] - L.opacity[0]),
          speed: L.speed,
          twinklePhase: rng() * Math.PI * 2,
          twinkleSpeed: 0.5 + rng() * 1.5,
          tint: rng() < 0.08 ? (rng() < 0.5 ? '#E5C07B' : '#C678DD')
              : rng() < 0.15 ? '#9ECBFF' : '#ffffff',
        });
      }
    });
    return out;
  }, [density, seed]);

  const nebulae = React.useMemo(() => {
    const rng = mulberry32(seed + 1);
    return [
      { x: 320,  y: 260, r: 540, color: '#4a1d5c', opacity: 0.28 },  // magenta cloud upper-left
      { x: 1500, y: 800, r: 620, color: '#1d3a5c', opacity: 0.32 },  // cyan cloud lower-right
      { x: 1700, y: 220, r: 380, color: '#5c3a1d', opacity: 0.22 },  // gold cloud upper-right
      { x: 180,  y: 900, r: 440, color: '#2d1d4a', opacity: 0.20 },  // purple cloud lower-left
    ];
  }, [seed]);

  const warp = warpAt(time);

  return (
    <div style={{
      position: 'absolute', inset: 0,
      overflow: 'hidden',
      pointerEvents: 'none',
      zIndex: 0,
      // Deep space base — center is DARKER so stars emerging from it feel
      // like they're coming out of the void toward the viewer.
      background: `
        radial-gradient(ellipse at 50% 50%, #010104 0%, #040412 40%, #06081a 75%, #020208 100%)
      `,
    }}>
      {/* Nebula clouds — soft blurred blobs, drift VERY slowly */}
      {nebulae.map((n, i) => {
        const drift = Math.sin(time * 0.03 + i) * 30;
        return (
          <div key={'n'+i} style={{
            position: 'absolute',
            left: n.x - n.r + drift,
            top: n.y - n.r + Math.cos(time * 0.025 + i) * 20,
            width: n.r * 2, height: n.r * 2,
            background: `radial-gradient(circle, ${n.color}${Math.floor(n.opacity * 255).toString(16).padStart(2, '0')} 0%, transparent 65%)`,
            filter: `blur(${50 + warp * 30}px)`,
            opacity: opacity * (1 - warp * 0.5), // nebulae recede during warp
          }}/>
        );
      })}

      {/* Stars — rendered as polar positions. Warp = radial outward + streak. */}
      <div style={{
        position: 'absolute', left: '50%', top: '50%',
        width: 0, height: 0,
      }}>
        {stars.map((star, i) => {
          // Slow outward drift at rest (lets stars feel alive without warp)
          const driftRadius = star.baseRadius + time * star.speed * 2;
          // In warp: push radius WAY outward, exponentially stronger at higher warp
          // Makes distant stars fly past the camera.
          const warpPush = warp * warp * star.speed * 1400;
          const r = driftRadius + warpPush;
          // Wrap stars that drift off-screen (keep the field full)
          const effectiveR = r % 1400;
          const x = Math.cos(star.angle) * effectiveR;
          const y = Math.sin(star.angle) * effectiveR;

          // Distance-based brightness — stars are dim far from center, bright when
          // they "reach" the viewer. Normalized to 0..1 across the radius range.
          const distNorm = Math.min(1, effectiveR / 900);
          const proximityBoost = warp > 0.1
            ? 0.3 + distNorm * 1.5  // in warp: dim at center, bright near edge
            : 1;

          // Twinkle (only at rest — during warp, stars are bright lines)
          const tw = warp > 0.1 ? 1 : (0.55 + 0.45 * Math.sin(time * star.twinkleSpeed + star.twinklePhase));

          // Length — during warp, stars become lines, length scales with warp²
          // and star speed, so near/fast stars streak the most.
          const length = warp > 0.05
            ? star.s + warp * warp * (80 + star.speed * 140) * (0.3 + distNorm)
            : star.s;
          const thickness = warp > 0.05
            ? Math.max(star.s * (0.5 + distNorm * 0.6), 0.6)
            : star.s;

          const alpha = Math.min(1, star.o * tw * opacity * proximityBoost);

          return (
            <div key={i} style={{
              position: 'absolute',
              left: 0, top: 0,
              width: length,
              height: thickness,
              background: warp > 0.05
                ? `linear-gradient(to right, transparent 0%, ${star.tint} 100%)`
                : star.tint,
              opacity: alpha,
              borderRadius: warp > 0.05 ? 1 : '50%',
              boxShadow: star.s > 2 && warp < 0.1 ? `0 0 ${star.s * 2}px ${star.tint}` : 'none',
              transform: `translate(${x - length/2}px, ${y - thickness/2}px) rotate(${star.angle}rad)`,
              transformOrigin: `${length/2}px ${thickness/2}px`,
            }}/>
          );
        })}
      </div>

      {/* Warp overlay — darker vignette (no cyan flash, center stays dark) */}
      {warp > 0.05 && (
        <div style={{
          position: 'absolute', inset: 0,
          background: `radial-gradient(circle at center, rgba(0,0,0,${warp * 0.6}) 0%, transparent 40%, rgba(0,0,0,${warp * 0.3}) 100%)`,
        }}/>
      )}
    </div>
  );
}

// ─── WarpTransition — just registers a window ──────────────────────────────
// Renders nothing visual. Its presence in the tree tells the Viewscreen to
// stretch stars during [start..end].
function WarpTransition({ start, end, intensity = 1.0 }) {
  const window = React.useMemo(() => ({ start, end, intensity }), [start, end, intensity]);
  React.useEffect(() => registerWarp(window), [window]);
  return null;
}

// ─── Gas Giant (optional accent) ───────────────────────────────────────────
function GasGiant({ x = 1500, y = 200, radius = 220, intensity = 0.6 }) {
  const { time } = useTimeline();
  const rotation = time * 2.5;
  return (
    <div style={{
      position: 'absolute',
      left: x - radius, top: y - radius,
      width: radius * 2, height: radius * 2,
      borderRadius: '50%',
      pointerEvents: 'none',
      zIndex: 1,
      opacity: intensity,
      background: `radial-gradient(circle at 35% 35%, #f4d19a 0%, #d9a875 25%, #a87443 55%, #4a2817 100%)`,
      boxShadow: `
        inset -${radius * 0.3}px -${radius * 0.2}px ${radius * 0.6}px rgba(0,0,0,0.55),
        inset ${radius * 0.2}px ${radius * 0.15}px ${radius * 0.5}px rgba(255, 220, 180, 0.25),
        0 0 ${radius * 0.4}px rgba(217, 168, 117, 0.2)
      `,
      overflow: 'hidden',
    }}>
      <div style={{
        position: 'absolute', inset: 0, borderRadius: '50%',
        background: `repeating-linear-gradient(
          0deg, transparent 0px,
          rgba(90, 50, 20, 0.18) ${radius * 0.08}px,
          transparent ${radius * 0.16}px,
          rgba(200, 150, 100, 0.12) ${radius * 0.24}px,
          transparent ${radius * 0.32}px)`,
        transform: `rotate(${rotation}deg)`,
      }}/>
      <div style={{
        position: 'absolute',
        left: `${52 + Math.cos(time * 0.1) * 2}%`,
        top: '55%',
        width: `${radius * 0.22}px`, height: `${radius * 0.15}px`,
        borderRadius: '50%',
        background: 'radial-gradient(ellipse at 50% 50%, #d14a3a 0%, #8a2a1c 60%, rgba(90, 25, 15, 0) 100%)',
        transform: 'translate(-50%, -50%)',
        filter: 'blur(1.5px)',
      }}/>
    </div>
  );
}

Object.assign(window, {
  Viewscreen, WarpTransition, GasGiant,
});
