#!/usr/bin/env node
/**
 * Local TTS generation for FalahMobile Learn content.
 * Uses macOS `say` + `afconvert` (fallback: ffmpeg/lame if available).
 * Reads prisma/seed-learn.json and generates MP3s for modules with audioPath.
 */

const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');

const PROJECT_ROOT = path.resolve(__dirname, '..');
const SEED_PATH = path.join(PROJECT_ROOT, 'prisma', 'seed-learn.json');
const PUBLIC_DIR = path.join(PROJECT_ROOT, 'public');

// Check available TTS tools
function detectTtsEngine() {
  try {
    execSync('which say', { stdio: 'ignore' });
    return { type: 'say', aiff: true };
  } catch {}
  try {
    execSync('which espeak', { stdio: 'ignore' });
    return { type: 'espeak', wav: true };
  } catch {}
  try {
    execSync('which piper', { stdio: 'ignore' });
    return { type: 'piper', wav: true };
  } catch {}
  return null;
}

function stripMarkdown(text) {
  return text
    .replace(/^---\n[\s\S]*?---\n/, '')
    .replace(/[\u{1F300}-\u{1F9FF}]/gu, ' ')
    .replace(/^#+\s+/gm, '')
    .replace(/\*\*?|\*\*?/g, '')
    .replace(/^>\s*/gm, '')
    .replace(/```[\s\S]*?```/g, '')
    .replace(/`[^`]+`/g, '')
    .replace(/^---+$/gm, '')
    .replace(/<[^>]+>/g, '')
    .replace(/\n{3,}/g, '\n\n')
    .trim();
}

function generateSayM4a(text, outputPath) {
  const tmpTxt = outputPath.replace(path.extname(outputPath), '.txt');
  fs.writeFileSync(tmpTxt, text, 'utf-8');
  try {
    // macOS say outputs AAC in .m4a directly with --file-format m4af
    execSync(`say -v "Samantha" --file-format m4af -f "${tmpTxt}" -o "${outputPath}"`, { stdio: 'ignore' });
    fs.unlinkSync(tmpTxt);
    return true;
  } catch (e) {
    console.error('  say failed:', e.message);
    try { fs.unlinkSync(tmpTxt); } catch {}
    return false;
  }
}

function generateEspeakWav(text, outputPath) {
  const tmpWav = outputPath.replace('.mp3', '.wav');
  try {
    execSync(`espeak -v en-us -s 150 -w "${tmpWav}" "${text.replace(/"/g, '\\"')}"`, { stdio: 'ignore' });
    // Convert WAV to MP3 via lame or ffmpeg
    try {
      execSync(`lame -V 7 "${tmpWav}" "${outputPath}"`, { stdio: 'ignore' });
    } catch {
      execSync(`ffmpeg -y -i "${tmpWav}" -codec:a libmp3lame -qscale:a 5 "${outputPath}"`, { stdio: 'ignore' });
    }
    fs.unlinkSync(tmpWav);
    return true;
  } catch (e) {
    console.error('  espeak failed:', e.message);
    try { fs.unlinkSync(tmpWav); } catch {}
    return false;
  }
}

function main() {
  const engine = detectTtsEngine();
  if (!engine) {
    console.error('No local TTS engine found. Install one of: say (macOS), espeak, piper');
    process.exit(1);
  }
  console.log(`Using TTS engine: ${engine.type}`);

  const seed = JSON.parse(fs.readFileSync(SEED_PATH, 'utf-8'));
  let generated = 0;
  let failed = 0;

  for (const course of seed.courses) {
    for (const mod of course.modules || []) {
      if (!mod.audioPath) continue;
      const outPath = path.join(PUBLIC_DIR, mod.audioPath);
      // Skip if already exists and > 1KB
      if (fs.existsSync(outPath) && fs.statSync(outPath).size > 1024) {
        console.log(`  SKIP (exists): ${mod.audioPath}`);
        continue;
      }

      // Ensure directory exists
      fs.mkdirSync(path.dirname(outPath), { recursive: true });

      const text = stripMarkdown(mod.content || mod.keyTakeaway || '');
      if (!text || text.length < 50) {
        console.log(`  SKIP (no content): ${mod.title}`);
        continue;
      }

      // Truncate to ~4000 chars to keep file sizes reasonable
      const ttsText = text.slice(0, 4000);
      console.log(`Generating: ${mod.audioPath} (${ttsText.length} chars)`);

      const ok = engine.type === 'say'
        ? generateSayM4a(ttsText, outPath)
        : generateEspeakWav(ttsText, outPath);

      if (ok) {
        generated++;
      } else {
        failed++;
      }
    }
  }

  console.log(`\nDone: ${generated} generated, ${failed} failed`);
}

main();
