// lib/sky.jsx — time of day, moon phase, sky colors, star fields

// ── Time of day model ──────────────────────────────────────
// Returns a number 0..1 across the day. We map to named phases.
function getSedonaHour(forced) {
  if (forced && forced !== 'auto') {
    const map = { dawn: 6.2, morning: 9.5, afternoon: 14.5, sunset: 18.7, twilight: 19.5, night: 22 };
    return map[forced] ?? 14;
  }
  // Sedona is Arizona time (no DST), UTC-7 year round.
  const now = new Date();
  const utcMin = now.getUTCHours() * 60 + now.getUTCMinutes();
  const local = ((utcMin - 7 * 60) % 1440 + 1440) % 1440;
  return local / 60;
}

function getPhase(hour) {
  if (hour < 5.5) return 'night';
  if (hour < 6.8) return 'dawn';
  if (hour < 11) return 'morning';
  if (hour < 17) return 'afternoon';
  if (hour < 19) return 'sunset';
  if (hour < 20.2) return 'twilight';
  return 'night';
}

// Sky gradient stops by phase
const SKY_GRADIENTS = {
  dawn:      ['#1a1f3a', '#48364a', '#9b5e4c', '#e9b08a'],
  morning:   ['#7eb4d8', '#b8d6e8', '#e7d8b6', '#f3e4c0'],
  afternoon: ['#4a8fc4', '#79b3da', '#bcd6e7', '#dfeaf0'],
  sunset:    ['#1a1530', '#3a2046', '#9b3a4b', '#d97243', '#f2b366'],
  twilight:  ['#0a1428', '#1c2a4c', '#3a3a66', '#6a4664', '#a85850'],
  night:     ['#040810', '#07111f', '#0d1a30', '#152545'],
};

// Sun/moon Y position (0 = top of viewport, 1 = horizon)
function getSunY(hour) {
  // Simple cos curve, peak at noon
  const t = (hour - 6) / 12; // 0 at sunrise, 1 at sunset
  if (t < 0 || t > 1) return 1.1; // below horizon
  return 0.95 - Math.sin(t * Math.PI) * 0.7;
}

function getMoonY(hour) {
  // Moon up at night-ish hours
  if (hour > 5 && hour < 18) return 1.1;
  const t = hour < 5 ? (hour + 6) / 12 : (hour - 18) / 12;
  return 0.92 - Math.sin(t * Math.PI) * 0.65;
}

// ── Moon phase calc (simplified, accurate enough for UX) ──
function getMoonPhase(date) {
  date = date || new Date();
  // Known new moon: 2000-01-06 18:14 UTC
  const ref = Date.UTC(2000, 0, 6, 18, 14);
  const synodic = 29.530588853;
  const days = (date.getTime() - ref) / 86400000;
  const phase = ((days % synodic) + synodic) % synodic;
  const fraction = phase / synodic; // 0..1
  let name, illum;
  illum = Math.round(50 * (1 - Math.cos(2 * Math.PI * fraction)));
  if (fraction < 0.03 || fraction > 0.97) name = 'New Moon';
  else if (fraction < 0.22) name = 'Waxing Crescent';
  else if (fraction < 0.28) name = 'First Quarter';
  else if (fraction < 0.47) name = 'Waxing Gibbous';
  else if (fraction < 0.53) name = 'Full Moon';
  else if (fraction < 0.72) name = 'Waning Gibbous';
  else if (fraction < 0.78) name = 'Last Quarter';
  else name = 'Waning Crescent';
  return { fraction, illum, name };
}

function moonBestFor(phase) {
  const { fraction, illum } = phase;
  if (illum > 80) return { tag: 'Moon Night', desc: 'Lunar craters & bright planets', tone: 'moon' };
  if (illum < 30) return { tag: 'Dark Sky Night', desc: 'Milky Way, galaxies, nebulae', tone: 'rock' };
  return { tag: 'Mixed Night', desc: 'Planets, double stars, brighter clusters', tone: 'juniper' };
}

// ── Star field generator (deterministic) ───────────────────
function seededRandom(seed) {
  let s = seed;
  return () => {
    s = (s * 9301 + 49297) % 233280;
    return s / 233280;
  };
}

function makeStars(count, seed = 7) {
  const r = seededRandom(seed);
  const out = [];
  for (let i = 0; i < count; i++) {
    out.push({
      x: r() * 100,
      y: r() * 70,
      size: 0.5 + r() * 1.8,
      dur: 2 + r() * 5,
      delay: r() * 4,
      max: 0.5 + r() * 0.5,
      min: 0.05 + r() * 0.3,
    });
  }
  return out;
}

Object.assign(window, {
  getSedonaHour, getPhase, SKY_GRADIENTS, getSunY, getMoonY,
  getMoonPhase, moonBestFor, makeStars, seededRandom,
});
