// palette.js — derive a cohesive, seed-driven world descriptor.
// One planet => one palette + terrain + flora + space appearance.
import * as THREE from 'three';
import { RNG, planetName, biomeTag, floraName, mineralName } from './util.js';

const hsl = (h, s, l) => new THREE.Color().setHSL(((h % 1) + 1) % 1, s, l);

// Biome templates guarantee two landed planets read as different WORLDS.
// Hues are 0..1. Each template jitters slightly by seed.
const TEMPLATES = [
  {
    key: 'coral-bio', biome: 'Bioluminescent',
    sky: [0.55, 0.62, 0.38], horizon: [0.49, 0.78, 0.72], // deep teal -> bright cyan
    groundLow: [0.95, 0.55, 0.55], groundHigh: [0.88, 0.45, 0.7], rock: [0.74, 0.25, 0.4], // coral/pink grass
    flora: [[0.78, 0.7, 0.6], [0.55, 0.8, 0.6], [0.9, 0.65, 0.62]], // purple/teal/magenta
    crystal: [0.5, 0.9, 0.6], sun: [0.09, 0.25, 0.97], sunI: 2.6, amb: [0.52, 0.5, 0.5], ambI: 0.85,
    space: [0.92, 0.5, 0.45], band: [0.55, 0.6, 0.55], cloud: [0.5, 0.2, 0.95], atmo: [0.5, 0.9, 0.6],
    terrain: { amp: 26, freq: 0.9, ridged: 0.25, oct: 5 }, fogD: 0.0050, fogC: [0.5, 0.5, 0.55], gravity: 0.55, ring: false,
  },
  {
    key: 'ochre-desert', biome: 'Scorched Dunes',
    sky: [0.33, 0.45, 0.5], horizon: [0.13, 0.6, 0.62], // green-gold sky
    groundLow: [0.09, 0.6, 0.42], groundHigh: [0.06, 0.55, 0.3], rock: [0.04, 0.5, 0.22],
    flora: [[0.05, 0.6, 0.4], [0.95, 0.5, 0.45], [0.12, 0.7, 0.45]],
    crystal: [0.03, 0.85, 0.55], sun: [0.08, 0.5, 0.99], sunI: 3.1, amb: [0.1, 0.4, 0.5], ambI: 0.7,
    space: [0.08, 0.6, 0.5], band: [0.1, 0.5, 0.4], cloud: [0.12, 0.3, 0.85], atmo: [0.12, 0.8, 0.6],
    terrain: { amp: 34, freq: 0.6, ridged: 0.55, oct: 5 }, fogD: 0.0044, fogC: [0.12, 0.5, 0.52], gravity: 0.7, ring: true,
  },
  {
    key: 'frozen', biome: 'Glass Tundra',
    sky: [0.62, 0.4, 0.62], horizon: [0.58, 0.45, 0.8],
    groundLow: [0.55, 0.18, 0.82], groundHigh: [0.6, 0.12, 0.92], rock: [0.6, 0.22, 0.55],
    flora: [[0.55, 0.7, 0.75], [0.5, 0.55, 0.7], [0.7, 0.6, 0.8]],
    crystal: [0.55, 0.85, 0.7], sun: [0.6, 0.12, 0.99], sunI: 2.4, amb: [0.6, 0.35, 0.62], ambI: 0.95,
    space: [0.58, 0.25, 0.78], band: [0.6, 0.15, 0.9], cloud: [0.6, 0.1, 0.98], atmo: [0.56, 0.7, 0.75],
    terrain: { amp: 30, freq: 0.7, ridged: 0.65, oct: 6 }, fogD: 0.0056, fogC: [0.58, 0.42, 0.66], gravity: 0.6, ring: false,
  },
  {
    key: 'toxic-fungal', biome: 'Fungal Expanse',
    sky: [0.16, 0.55, 0.5], horizon: [0.2, 0.7, 0.55],
    groundLow: [0.26, 0.6, 0.4], groundHigh: [0.3, 0.7, 0.45], rock: [0.18, 0.4, 0.3],
    flora: [[0.85, 0.75, 0.6], [0.92, 0.7, 0.62], [0.33, 0.8, 0.55]],
    crystal: [0.28, 0.9, 0.6], sun: [0.15, 0.4, 0.96], sunI: 2.3, amb: [0.22, 0.45, 0.5], ambI: 0.9,
    space: [0.28, 0.6, 0.42], band: [0.85, 0.5, 0.5], cloud: [0.2, 0.3, 0.8], atmo: [0.28, 0.85, 0.6],
    terrain: { amp: 22, freq: 1.0, ridged: 0.2, oct: 5 }, fogD: 0.0062, fogC: [0.22, 0.55, 0.48], gravity: 0.5, ring: false,
  },
  {
    key: 'ember-volcanic', biome: 'Crimson Mesa',
    sky: [0.99, 0.6, 0.42], horizon: [0.04, 0.8, 0.5],
    groundLow: [0.03, 0.55, 0.34], groundHigh: [0.06, 0.45, 0.24], rock: [0.0, 0.4, 0.18],
    flora: [[0.08, 0.85, 0.55], [0.99, 0.75, 0.58], [0.12, 0.9, 0.6]],
    crystal: [0.05, 0.95, 0.62], sun: [0.05, 0.6, 0.99], sunI: 3.0, amb: [0.03, 0.6, 0.5], ambI: 1.0,
    space: [0.02, 0.55, 0.32], band: [0.06, 0.6, 0.4], cloud: [0.04, 0.4, 0.7], atmo: [0.03, 0.9, 0.55],
    terrain: { amp: 40, freq: 0.55, ridged: 0.7, oct: 6 }, fogD: 0.0050, fogC: [0.05, 0.7, 0.42], gravity: 0.85, ring: false,
  },
  {
    key: 'aurora-night', biome: 'Aurora Fields',
    sky: [0.68, 0.6, 0.18], horizon: [0.55, 0.7, 0.32],
    groundLow: [0.66, 0.45, 0.28], groundHigh: [0.6, 0.5, 0.35], rock: [0.7, 0.3, 0.22],
    flora: [[0.45, 0.85, 0.6], [0.55, 0.9, 0.62], [0.75, 0.8, 0.6]],
    crystal: [0.48, 0.95, 0.62], sun: [0.6, 0.3, 0.8], sunI: 1.6, amb: [0.62, 0.5, 0.42], ambI: 1.1,
    space: [0.66, 0.5, 0.3], band: [0.5, 0.6, 0.4], cloud: [0.55, 0.4, 0.7], atmo: [0.5, 0.9, 0.62],
    terrain: { amp: 28, freq: 0.8, ridged: 0.4, oct: 5 }, fogD: 0.0072, fogC: [0.6, 0.5, 0.32], gravity: 0.45, ring: false,
  },
];

function jcol(rng, [h, s, l], hj = 0.02, sj = 0.06, lj = 0.05) {
  return hsl(h + rng.range(-hj, hj), THREE.MathUtils.clamp(s + rng.range(-sj, sj), 0, 1), THREE.MathUtils.clamp(l + rng.range(-lj, lj), 0, 1));
}

export function makePlanet(seed, templateIndex = null) {
  const rng = new RNG(seed);
  const t = TEMPLATES[templateIndex != null ? templateIndex % TEMPLATES.length : rng.int(0, TEMPLATES.length - 1)];
  const nameRng = new RNG(seed ^ 0x9e3779b9);

  const flora = t.flora.map((c) => jcol(rng, c));
  const archetypes = pickArchetypes(rng, flora);

  return {
    seed,
    key: t.key,
    name: planetName(nameRng),
    biome: t.biome,
    colors: {
      skyTop: jcol(rng, t.sky),
      skyHorizon: jcol(rng, t.horizon),
      fog: jcol(rng, t.fogC, 0.02, 0.06, 0.03),
      sun: jcol(rng, t.sun, 0.01, 0.05, 0.02),
      ambient: jcol(rng, t.amb),
      groundLow: jcol(rng, t.groundLow),
      groundHigh: jcol(rng, t.groundHigh),
      rock: jcol(rng, t.rock),
      crystal: jcol(rng, t.crystal, 0.01, 0.04, 0.04),
      atmosphere: jcol(rng, t.atmo),
      spaceBase: jcol(rng, t.space),
      spaceBand: jcol(rng, t.band),
      spaceCloud: jcol(rng, t.cloud),
    },
    sunIntensity: t.sunI * rng.range(0.92, 1.08),
    ambientIntensity: t.ambI * rng.range(0.92, 1.08),
    fogDensity: t.fogD * rng.range(0.9, 1.1),
    gravity: t.gravity,
    terrain: {
      amp: t.terrain.amp * rng.range(0.9, 1.1),
      freq: t.terrain.freq * rng.range(0.85, 1.15),
      ridged: t.terrain.ridged,
      oct: t.terrain.oct,
      seed: seed ^ 0x1234567,
    },
    hasRing: t.ring,
    flora,
    archetypes,
    floraNames: archetypes.map(() => floraName(new RNG((seed * 131 + Math.floor(rng.next() * 1e6)) >>> 0))),
    mineralName: mineralName(new RNG(seed ^ 0xabcdef)),
  };
}

// Choose 4-6 flora archetypes with seed-driven proportions.
const ARCH_KINDS = ['tubeTree', 'balloon', 'coralFan', 'crystalCluster', 'sporeStalk', 'frondFan'];
function pickArchetypes(rng, flora) {
  const count = rng.int(4, 6);
  const kinds = ARCH_KINDS.slice();
  // shuffle
  for (let i = kinds.length - 1; i > 0; i--) {
    const j = rng.int(0, i);
    [kinds[i], kinds[j]] = [kinds[j], kinds[i]];
  }
  const chosen = kinds.slice(0, count);
  // ensure a crystalCluster exists for mining-flavored scatter look
  if (!chosen.includes('crystalCluster')) chosen[0] = 'crystalCluster';
  return chosen.map((kind, i) => ({
    kind,
    color: flora[i % flora.length],
    accent: flora[(i + 1) % flora.length],
    height: rng.range(0.7, 1.8),
    girth: rng.range(0.7, 1.5),
    lean: rng.range(-0.18, 0.18),
    parts: rng.int(2, 5),
    emissive: rng.range(0.15, 0.7),
  }));
}
