import { NextResponse } from 'next/server';
import { exec } from 'child_process';
import { promisify } from 'util';
import { access, stat, readdir } from 'fs/promises';
import { join, resolve } from 'path';

const execAsync = promisify(exec);

const IS_MAC = process.platform === 'darwin';

// process.cwd() = dashboard/, parent = __LOCAL_LLMs/
const LOCAL_LLMS_DIR = resolve(process.cwd(), '..');

// macOS/Linux: bin/python, Windows native: Scripts/python.exe
const VENV_PYTHON = join(LOCAL_LLMS_DIR, '.venv-qwen-tts', 'bin', 'python');

interface TtsEngine {
  name: string;
  type: 'ollama' | 'python';
  status: 'ready' | 'partial' | 'missing';
  model: string;
  size?: string;
  voices?: string[];
  details: string;
}

async function fileExists(path: string): Promise<boolean> {
  try {
    await access(path);
    return true;
  } catch {
    return false;
  }
}

async function getFileSize(path: string): Promise<number> {
  try {
    const s = await stat(path);
    return s.size;
  } catch {
    return 0;
  }
}

async function checkOrpheus(): Promise<TtsEngine> {
  const engine: TtsEngine = {
    name: 'Orpheus TTS',
    type: 'ollama',
    status: 'missing',
    model: 'sematre/orpheus:en',
    voices: ['tara', 'leah', 'jess', 'leo', 'dan', 'mia', 'zac', 'zoe'],
    details: '',
  };

  // Check if Orpheus model is in Ollama
  let hasModel = false;
  try {
    const res = await fetch('http://localhost:11434/api/tags', {
      signal: AbortSignal.timeout(2000),
    });
    if (res.ok) {
      const data = await res.json();
      hasModel = data.models?.some((m: { name: string }) => m.name.includes('orpheus')) ?? false;
    }
  } catch {
    // Ollama not running
  }

  // Check SNAC decoder
  const snacPath = join(LOCAL_LLMS_DIR, 'models', 'snac_24khz', 'pytorch_model.bin');
  const hasSnac = await fileExists(snacPath);
  const snacSize = hasSnac ? await getFileSize(snacPath) : 0;

  // Check Python venv
  const hasVenv = await fileExists(VENV_PYTHON);

  if (hasModel && hasSnac && hasVenv) {
    engine.status = 'ready';
    engine.size = `${(snacSize / 1e6).toFixed(0)} MB decoder`;
    engine.details = 'Ollama model + SNAC decoder + Python venv';
  } else if (hasModel) {
    engine.status = 'partial';
    const missing: string[] = [];
    if (!hasSnac) missing.push('SNAC decoder');
    if (!hasVenv) missing.push('Python venv');
    engine.details = `Missing: ${missing.join(', ')}`;
  } else {
    engine.status = 'missing';
    engine.details = 'Run: bash setup-tts.sh';
  }

  return engine;
}

async function checkQwenTts(): Promise<TtsEngine> {
  const engine: TtsEngine = {
    name: 'Qwen3-TTS',
    type: 'python',
    status: 'missing',
    model: 'Qwen3-TTS-12Hz-0.6B-CustomVoice',
    details: '',
  };

  const modelDir = join(LOCAL_LLMS_DIR, 'models', 'Qwen3-TTS-12Hz-0.6B-CustomVoice');
  const tokenizerDir = join(LOCAL_LLMS_DIR, 'models', 'Qwen3-TTS-Tokenizer-12Hz');

  let hasModel = false;
  let modelSize = 0;
  try {
    const files = await readdir(modelDir);
    const safetensors = files.find(f => f.endsWith('.safetensors'));
    if (safetensors) {
      hasModel = true;
      modelSize = await getFileSize(join(modelDir, safetensors));
    }
  } catch {
    // dir doesn't exist
  }

  const hasTokenizer = await fileExists(join(tokenizerDir, 'config.json'));
  const hasVenv = await fileExists(VENV_PYTHON);

  if (hasModel && hasTokenizer && hasVenv) {
    engine.status = 'ready';
    engine.size = `${(modelSize / 1e9).toFixed(1)} GB`;
    engine.details = IS_MAC
      ? '0.6B params · 10 languages · MPS/CPU'
      : '0.6B params · 10 languages · CUDA/CPU';
  } else if (hasModel || hasTokenizer) {
    engine.status = 'partial';
    const missing: string[] = [];
    if (!hasModel) missing.push('model weights');
    if (!hasTokenizer) missing.push('tokenizer');
    if (!hasVenv) missing.push('Python venv');
    engine.details = `Missing: ${missing.join(', ')}`;
  } else {
    engine.status = 'missing';
    engine.details = 'Run: bash setup-tts.sh';
  }

  return engine;
}

async function checkVenv(): Promise<{
  exists: boolean;
  python?: string;
  packages?: string[];
}> {
  const exists = await fileExists(VENV_PYTHON);
  if (!exists) return { exists: false };

  try {
    const { stdout } = await execAsync(
      `"${VENV_PYTHON}" -c "import snac; import torch; print(f'snac={snac.__version__} torch={torch.__version__}')"`,
      { timeout: 5000 }
    );
    return {
      exists: true,
      python: VENV_PYTHON,
      packages: stdout.trim().split(' '),
    };
  } catch {
    return { exists: true, python: VENV_PYTHON };
  }
}

export async function GET() {
  const [orpheus, qwenTts, venv] = await Promise.all([checkOrpheus(), checkQwenTts(), checkVenv()]);

  return NextResponse.json({
    engines: [orpheus, qwenTts],
    venv,
    setupScript: 'bash setup-tts.sh',
    testCommands: {
      orpheus: '.venv-qwen-tts/bin/python test_orpheus_tts.py',
      qwenTts: '.venv-qwen-tts/bin/python test_qwen_tts.py',
    },
  });
}
