// gen-music-placeholders.js
// Synthesizes short loopable ambient WAV files (one per mood) using only Node stdlib.
// Output: media/music/<mood>.wav
// Each file: mono, 16-bit, 22050 Hz, ~8 seconds, low-amplitude, non-silent.
// License: CC0 (synthesized placeholder — replace with real DRM-free tracks).

const fs = require('fs');
const path = require('path');

const SAMPLE_RATE = 22050;
const DURATION_SEC = 8;
const NUM_SAMPLES = SAMPLE_RATE * DURATION_SEC;
const BITS_PER_SAMPLE = 16;
const BYTES_PER_SAMPLE = BITS_PER_SAMPLE / 8;
const CHANNELS = 1;

const MOODS = {
  combat: {
    title: 'Combat — Driving Tension',
    // Fast pulsing low sine + harsh high noise burst
    generate(i) {
      const t = i / SAMPLE_RATE;
      const pulse = Math.sin(2 * Math.PI * 80 * t) * 0.15;
      const drive = Math.sin(2 * Math.PI * 160 * t) * 0.08;
      const noise = (Math.random() * 2 - 1) * 0.04;
      const accent = Math.sin(2 * Math.PI * 40 * t) * Math.sin(2 * Math.PI * 2 * t) * 0.1;
      return pulse + drive + noise + accent;
    },
  },
  investigation: {
    title: 'Investigation — Low Ambient Drone',
    generate(i) {
      const t = i / SAMPLE_RATE;
      const drone1 = Math.sin(2 * Math.PI * 55 * t) * 0.12;
      const drone2 = Math.sin(2 * Math.PI * 82.5 * t) * 0.08;
      const sub = Math.sin(2 * Math.PI * 30 * t) * 0.1;
      const shimmer = Math.sin(2 * Math.PI * 220 * t) * 0.02 * Math.sin(2 * Math.PI * 0.25 * t);
      return drone1 + drone2 + sub + shimmer;
    },
  },
  tension: {
    title: 'Tension — Ominous Unease',
    generate(i) {
      const t = i / SAMPLE_RATE;
      const low = Math.sin(2 * Math.PI * 45 * t) * 0.12;
      const dissonance = Math.sin(2 * Math.PI * 67 * t) * 0.08;
      const trill = Math.sin(2 * Math.PI * 330 * t) * 0.03 * (1 + 0.5 * Math.sin(2 * Math.PI * 3 * t));
      const scrape = (Math.random() * 2 - 1) * 0.02 * Math.abs(Math.sin(2 * Math.PI * 1.5 * t));
      return low + dissonance + trill + scrape;
    },
  },
  victory: {
    title: 'Victory — Warm Resolution',
    generate(i) {
      const t = i / SAMPLE_RATE;
      const root = Math.sin(2 * Math.PI * 130.8 * t) * 0.12;
      const third = Math.sin(2 * Math.PI * 164.8 * t) * 0.09;
      const fifth = Math.sin(2 * Math.PI * 196 * t) * 0.07;
      const octave = Math.sin(2 * Math.PI * 261.6 * t) * 0.05;
      const warmth = Math.sin(2 * Math.PI * 65.4 * t) * 0.08;
      return root + third + fifth + octave + warmth;
    },
  },
  eerie: {
    title: 'Eerie — Dissonant Sparse',
    generate(i) {
      const t = i / SAMPLE_RATE;
      const sparse = Math.sin(2 * Math.PI * 110 * t) * 0.06 * (Math.sin(2 * Math.PI * 0.15 * t) > 0.5 ? 1 : 0.05);
      const dissonant = Math.sin(2 * Math.PI * 117 * t) * 0.06 * (Math.sin(2 * Math.PI * 0.15 * t) > 0.5 ? 1 : 0.05);
      const whisper = (Math.random() * 2 - 1) * 0.015 * (Math.sin(2 * Math.PI * 0.5 * t) > 0 ? 1 : 0);
      const sub = Math.sin(2 * Math.PI * 25 * t) * 0.08;
      return sparse + dissonant + whisper + sub;
    },
  },
};

function writeWav(filePath, samples) {
  const numBytes = samples.length * BYTES_PER_SAMPLE;
  const buf = Buffer.alloc(44 + numBytes);

  // RIFF header
  buf.write('RIFF', 0);
  buf.writeUInt32LE(36 + numBytes, 4);
  buf.write('WAVE', 8);

  // fmt chunk
  buf.write('fmt ', 12);
  buf.writeUInt32LE(16, 16);
  buf.writeUInt16LE(1, 20);  // PCM
  buf.writeUInt16LE(CHANNELS, 22);
  buf.writeUInt32LE(SAMPLE_RATE, 24);
  buf.writeUInt32LE(SAMPLE_RATE * BYTES_PER_SAMPLE * CHANNELS, 28);
  buf.writeUInt16LE(BYTES_PER_SAMPLE * CHANNELS, 32);
  buf.writeUInt16LE(BITS_PER_SAMPLE, 34);

  // data chunk
  buf.write('data', 36);
  buf.writeUInt32LE(numBytes, 40);

  for (let i = 0; i < samples.length; i++) {
    let val = samples[i];
    // Clamp to [-1, 1]
    if (val > 1) val = 1;
    if (val < -1) val = -1;
    // Convert to signed 16-bit
    const int16 = val >= 0 ? Math.floor(val * 32767) : Math.ceil(val * 32768);
    buf.writeInt16LE(int16, 44 + i * BYTES_PER_SAMPLE);
  }

  fs.writeFileSync(filePath, buf);
}

function generateMood(mood, config) {
  const samples = [];
  for (let i = 0; i < NUM_SAMPLES; i++) {
    samples.push(config.generate(i));
  }
  return samples;
}

// Main
const outDir = path.join(__dirname, '..', 'media', 'music');
fs.mkdirSync(outDir, { recursive: true });

const manifest = [];

for (const [mood, config] of Object.entries(MOODS)) {
  const samples = generateMood(mood, config);
  const filePath = path.join(outDir, `${mood}.wav`);
  writeWav(filePath, samples);

  // Verify non-silent
  let maxAmp = 0;
  for (const s of samples) {
    if (Math.abs(s) > maxAmp) maxAmp = Math.abs(s);
  }

  console.log(`Generated: ${filePath}  (${samples.length} samples, max amplitude: ${maxAmp.toFixed(4)})`);

  manifest.push({
    mood,
    file: `${mood}.wav`,
    title: config.title,
    license: 'CC0 (synthesized placeholder)',
  });
}

// Write manifest
const manifestPath = path.join(outDir, 'manifest.json');
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
console.log(`\nManifest written: ${manifestPath}`);
console.log('Done. All placeholder tracks are CC0 synthesized audio.');