import { execSync } from 'child_process'
import { writeFileSync, unlinkSync, existsSync, mkdirSync } from 'fs'
import { join } from 'path'

/**
 * Server-side voice command recognition using whisper.cpp.
 * Optimized for short utterances: "Done" / "Fertig" / "Repeat" / "Wiederholen".
 *
 * POST /api/mobile/voice-command
 * Body: multipart form — 'audio' file
 *
 * Returns: { command: 'done' | 'repeat' | 'unknown', transcript: string }
 */

const DONE_KEYWORDS = ['done', 'fertig', 'erledigt', 'weiter', 'next', 'nächste', 'ok']
const REPEAT_KEYWORDS = ['repeat', 'wiederholen', 'nochmal', 'noch mal', 'again', 'erneut']

const detectCommand = (text: string): 'done' | 'repeat' | 'unknown' => {
  const lower = text.toLowerCase().trim()
  if (!lower) return 'unknown'

  for (const kw of DONE_KEYWORDS) {
    if (lower.includes(kw)) return 'done'
  }
  for (const kw of REPEAT_KEYWORDS) {
    if (lower.includes(kw)) return 'repeat'
  }
  return 'unknown'
}

export default defineEventHandler(async (event) => {
  const formData = await readMultipartFormData(event)
  if (!formData) {
    return { status: 400, command: 'unknown', transcript: '', message: 'Multipart form data required' }
  }

  let audioBuffer: Buffer | null = null
  let audioFilename = 'cmd.webm'
  let language = 'en'

  for (const part of formData) {
    if (part.name === 'audio') {
      audioBuffer = part.data
      audioFilename = part.filename || 'cmd.webm'
    } else if (part.name === 'language') {
      language = part.data.toString() || 'en'
    }
  }

  if (!audioBuffer) {
    return { status: 400, command: 'unknown', transcript: '', message: 'Audio file required' }
  }

  // Save audio to temp file
  const tmpDir = join(process.cwd(), '.tmp-voice-cmd')
  if (!existsSync(tmpDir)) mkdirSync(tmpDir, { recursive: true })

  const audioPath = join(tmpDir, `${Date.now()}-${audioFilename}`)
  const wavPath = audioPath.replace(/\.\w+$/, '.wav')

  try {
    writeFileSync(audioPath, audioBuffer)

    // Convert to WAV 16kHz mono
    try {
      execSync(`ffmpeg -i "${audioPath}" -ar 16000 -ac 1 -y "${wavPath}" 2>/dev/null`, { timeout: 15000 })
    } catch (e: any) {
      console.error('[VoiceCmd] ffmpeg conversion failed:', e.message)
      return { status: 500, command: 'unknown', transcript: '', message: 'Audio conversion failed' }
    }

    // Transcribe with whisper.cpp
    const persistentDir = '/opt/whisper-cpp'
    const nodeModulesDir = join(process.cwd(), 'node_modules/whisper-node/lib/whisper.cpp')
    const whisperBin = existsSync(join(persistentDir, 'main')) ? join(persistentDir, 'main') : join(nodeModulesDir, 'main')
    const modelFile = existsSync(join(persistentDir, 'ggml-base.bin')) ? join(persistentDir, 'ggml-base.bin') : join(nodeModulesDir, 'models/ggml-base.bin')

    if (!existsSync(whisperBin) || !existsSync(modelFile)) {
      return { status: 500, command: 'unknown', transcript: '', message: 'Whisper not available' }
    }

    // Use short language code for whisper
    const whisperLang = language === 'de-DE' || language === 'de' ? 'de' : 'en'

    let whisperOutput: string
    try {
      whisperOutput = execSync(
        `"${whisperBin}" -m "${modelFile}" -l ${whisperLang} -f "${wavPath}"`,
        { timeout: 30000, encoding: 'utf-8' }
      )
    } catch (e: any) {
      console.error('[VoiceCmd] Whisper failed:', e.stderr || e.message)
      return { status: 500, command: 'unknown', transcript: '', message: 'Transcription failed' }
    }

    // Parse whisper output
    const segments = whisperOutput
      .split('\n')
      .filter(line => line.includes('-->'))
      .map(line => {
        const match = line.match(/\]\s*(.*)$/)
        return match ? match[1].trim() : ''
      })
      .filter(Boolean)

    const transcript = segments.join(' ').trim()
    const command = detectCommand(transcript)

    console.log(`[VoiceCmd] transcript="${transcript}" → command=${command}`)
    return { status: 200, command, transcript }

  } finally {
    try { if (existsSync(audioPath)) unlinkSync(audioPath) } catch {}
    try { if (existsSync(wavPath)) unlinkSync(wavPath) } catch {}
  }
})
