// biome-creature.jsx — procedural bioluminescent on-chain creature renderer
// Exports (to window): Creature, SPECIES, makeCreature, dnaHex

// ── Species palettes (hue, accent hue, name, glyph) ───────────────
const SPECIES = {
  lumen: { name: 'Lumen', hue: 268, accent: 286, body: 'orb',    blurb: 'Violet drifters. Photosynthesize raw blockspace.' },
  drift: { name: 'Drift', hue: 188, accent: 168, body: 'jelly',  blurb: 'Tidal jellies. Pulse once per Monad block.' },
  nyx:   { name: 'Nyx',   hue: 322, accent: 340, body: 'orb',    blurb: 'Magenta wisps. Bred in the dark mempool.' },
  sol:   { name: 'Sol',   hue: 44,  accent: 26,  body: 'star',   blurb: 'Ember spores. Hottest signatures on-chain.' },
  echo:  { name: 'Echo',  hue: 214, accent: 232, body: 'jelly',  blurb: 'Deep-blue listeners. Mirror nearby creatures.' },
};
const STAGES = ['Spore', 'Larva', 'Bloom', 'Apex'];

// deterministic tiny PRNG from a seed string
function rng(seedStr) {
  let h = 1779033703 ^ seedStr.length;
  for (let i = 0; i < seedStr.length; i++) {
    h = Math.imul(h ^ seedStr.charCodeAt(i), 3432918353);
    h = (h << 13) | (h >>> 19);
  }
  return function () {
    h = Math.imul(h ^ (h >>> 16), 2246822507);
    h = Math.imul(h ^ (h >>> 13), 3266489909);
    h ^= h >>> 16;
    return (h >>> 0) / 4294967296;
  };
}

function dnaHex(seed) {
  const r = rng(seed + 'dna');
  let s = '0x';
  for (let i = 0; i < 8; i++) s += Math.floor(r() * 16).toString(16);
  s += '…';
  for (let i = 0; i < 4; i++) s += Math.floor(r() * 16).toString(16);
  return s;
}

// Build a creature data object from a seed + chosen species + stage
function makeCreature(seed, speciesKey, stage = 2, overrides = {}) {
  const r = rng(seed);
  const sp = SPECIES[speciesKey];
  return {
    id: seed,
    species: speciesKey,
    name: overrides.name || sp.name,
    stage,
    stageName: STAGES[stage - 1],
    gen: overrides.gen != null ? overrides.gen : 1 + Math.floor(r() * 6),
    token: overrides.token || ('#' + (1000 + Math.floor(r() * 8999))),
    hueShift: Math.floor(r() * 24) - 12,
    eyes: stage >= 3 ? (r() > 0.6 ? 3 : 2) : (r() > 0.4 ? 2 : 1),
    spots: 3 + Math.floor(r() * 5),
    tendrils: Math.min(2 + stage, 6),
    wobble: 0.85 + r() * 0.4,
    energy: overrides.energy != null ? overrides.energy : 40 + Math.floor(r() * 55),
    evolve: overrides.evolve != null ? overrides.evolve : Math.floor(r() * 90),
    dna: dnaHex(seed),
    ...overrides,
  };
}

// ── The renderer ──────────────────────────────────────────────────
function Creature({ c, size = 160, lively = 1, glow = 1, idle = false, dormant = false }) {
  const sp = SPECIES[c.species];
  const dorm = dormant || (c.energy != null && c.energy <= 10);
  const still = idle || dorm;
  const hue = (sp.hue + (c.hueShift || 0) + 360) % 360;
  const acc = (sp.accent + (c.hueShift || 0) + 360) % 360;
  const uid = 'cr' + c.id.replace(/[^a-z0-9]/gi, '');
  const r = rng(c.id + 'render');

  const light = `hsl(${hue} 95% 78%)`;
  const mid = `hsl(${hue} 88% 62%)`;
  const deep = `hsl(${hue} 80% 42%)`;
  const accC = `hsl(${acc} 95% 72%)`;
  const dur = (base) => `${(base / Math.max(0.15, lively)).toFixed(2)}s`;

  // body radius by stage
  const scale = 0.62 + c.stage * 0.11;
  const bodyR = 46 * scale;

  // spots
  const spots = [];
  for (let i = 0; i < c.spots; i++) {
    const a = r() * Math.PI * 2;
    const rr = r() * bodyR * 0.62;
    spots.push({ x: 100 + Math.cos(a) * rr, y: 96 + Math.sin(a) * rr * 0.9, s: 2 + r() * 4 });
  }
  // tendrils
  const tendrils = [];
  for (let i = 0; i < c.tendrils; i++) {
    const t = (i / (c.tendrils - 1 || 1) - 0.5) * 1.5;
    const x = 100 + t * bodyR * 0.9;
    tendrils.push({ x, sway: 3 + r() * 4, len: bodyR * (0.7 + r() * 0.7), delay: r() * 2 });
  }
  // eyes
  const eyes = [];
  const eyeGap = c.eyes === 1 ? 0 : bodyR * 0.34;
  for (let i = 0; i < c.eyes; i++) {
    const ex = 100 + (i - (c.eyes - 1) / 2) * eyeGap;
    eyes.push({ x: ex, y: 88 - bodyR * 0.04 });
  }

  return (
    <div style={{ width: size, height: size, display: 'inline-block', lineHeight: 0,
      filter: dorm ? 'saturate(0.28) brightness(0.62)' : 'none', transition: 'filter .6s ease',
      animation: still ? 'none' : `bobFloat ${dur(5.5)} ease-in-out infinite`, animationDelay: `${(r() * -3).toFixed(2)}s` }}>
      <svg viewBox="0 0 200 200" width={size} height={size} style={{ overflow: 'visible' }}>
        <defs>
          <radialGradient id={uid + 'body'} cx="42%" cy="34%" r="75%">
            <stop offset="0%" stopColor={light} />
            <stop offset="55%" stopColor={mid} />
            <stop offset="100%" stopColor={deep} />
          </radialGradient>
          <radialGradient id={uid + 'glow'} cx="50%" cy="50%" r="50%">
            <stop offset="0%" stopColor={mid} stopOpacity={0.7 * glow} />
            <stop offset="60%" stopColor={mid} stopOpacity={0.18 * glow} />
            <stop offset="100%" stopColor={mid} stopOpacity="0" />
          </radialGradient>
          <filter id={uid + 'soft'} x="-60%" y="-60%" width="220%" height="220%">
            <feGaussianBlur stdDeviation="3.2" />
          </filter>
        </defs>

        {/* outer glow halo */}
        <ellipse cx="100" cy="100" rx={bodyR * 1.95} ry={bodyR * 1.95} fill={`url(#${uid}glow)`}
          opacity={dorm ? 0.3 : 1}
          style={{ animation: dorm ? 'none' : `glowPulse ${dur(3.2)} ease-in-out infinite`, transformOrigin: '100px 100px' }} />

        {/* tendrils behind body */}
        <g style={{ animation: still ? 'none' : `sway ${dur(4)} ease-in-out infinite` }}>
          {tendrils.map((t, i) => (
            <path key={i}
              d={`M ${t.x} ${100 + bodyR * 0.55} q ${t.sway} ${t.len * 0.5} 0 ${t.len} q ${-t.sway} ${t.len * 0.4} 0 ${t.len * 0.5}`}
              fill="none" stroke={accC} strokeWidth={2.4 + c.stage * 0.4} strokeLinecap="round"
              opacity="0.75"
              style={{ transformOrigin: `${t.x}px ${100 + bodyR * 0.5}px`, animation: still ? 'none' : `tendril ${dur(3.6 + t.delay)} ease-in-out infinite`, animationDelay: `${(-t.delay).toFixed(2)}s` }} />
          ))}
        </g>

        {/* side fins for jelly/star bodies */}
        {(sp.body !== 'orb') && [-1, 1].map((s) => (
          <ellipse key={s} cx={100 + s * bodyR * 0.92} cy="98" rx={bodyR * 0.34} ry={bodyR * 0.6}
            fill={mid} opacity="0.45" filter={`url(#${uid}soft)`}
            transform={`rotate(${s * 16} ${100 + s * bodyR * 0.92} 98)`} />
        ))}

        {/* body — breathing */}
        <g style={{ transformOrigin: '100px 96px', animation: still ? 'none' : `breathe ${dur(3.4)} ease-in-out infinite` }}>
          {sp.body === 'star' ? (
            <path d={starPath(100, 96, bodyR, bodyR * 0.66, 7)} fill={`url(#${uid}body)`} />
          ) : (
            <ellipse cx="100" cy="96" rx={bodyR * (sp.body === 'jelly' ? 1.02 : 0.96)} ry={bodyR * (sp.body === 'jelly' ? 0.86 : 1)}
              fill={`url(#${uid}body)`} />
          )}
          {/* inner rim light */}
          <ellipse cx="92" cy="82" rx={bodyR * 0.4} ry={bodyR * 0.28} fill="#fff" opacity="0.28" filter={`url(#${uid}soft)`} />

          {/* glowing spots */}
          {spots.map((s, i) => (
            <circle key={i} cx={s.x} cy={s.y} r={s.s} fill={accC} opacity="0.85"
              style={{ animation: `twinkle ${dur(2 + (i % 3))} ease-in-out infinite`, animationDelay: `${(-i * 0.3).toFixed(2)}s` }} />
          ))}

          {/* eyes — blink (closed when dormant) */}
          <g style={{ transformOrigin: '100px 88px', animation: still ? 'none' : `blink ${dur(4.5)} ease-in-out infinite` }}>
            {eyes.map((e, i) => dorm ? (
              <path key={i} d={`M ${e.x - bodyR * 0.15} ${e.y} q ${bodyR * 0.15} ${bodyR * 0.13} ${bodyR * 0.3} 0`}
                fill="none" stroke="#0c0716" strokeWidth={bodyR * 0.07} strokeLinecap="round" opacity="0.8" />
            ) : (
              <g key={i}>
                <circle cx={e.x} cy={e.y} r={bodyR * 0.16} fill="#0c0716" opacity="0.92" />
                <circle cx={e.x + 1.5} cy={e.y - 1.5} r={bodyR * 0.05} fill="#fff" />
              </g>
            ))}
          </g>

          {/* antennae for Apex */}
          {c.stage >= 4 && [-1, 1].map((s) => (
            <g key={s}>
              <line x1={100 + s * bodyR * 0.3} y1={96 - bodyR * 0.9} x2={100 + s * bodyR * 0.55} y2={96 - bodyR * 1.4}
                stroke={accC} strokeWidth="2.2" strokeLinecap="round" />
              <circle cx={100 + s * bodyR * 0.55} cy={96 - bodyR * 1.4} r="3.4" fill={accC}
                style={{ animation: `twinkle ${dur(1.8)} ease-in-out infinite` }} />
            </g>
          ))}
        </g>
      </svg>
    </div>
  );
}

function starPath(cx, cy, outer, inner, points) {
  let d = '';
  for (let i = 0; i < points * 2; i++) {
    const r = i % 2 === 0 ? outer : inner;
    const a = (i / (points * 2)) * Math.PI * 2 - Math.PI / 2;
    d += (i === 0 ? 'M' : 'L') + (cx + Math.cos(a) * r).toFixed(1) + ' ' + (cy + Math.sin(a) * r).toFixed(1) + ' ';
  }
  return d + 'Z';
}

Object.assign(window, { Creature, SPECIES, STAGES, makeCreature, dnaHex });
