/**
 * speech.js — 语音消息转文字
 *
 * 流程：飞书音频（ogg/amr/m4a）→ ffmpeg 转 mp3 → Whisper API → 文字
 *
 * 环境变量：
 *   WHISPER_API_KEY     API Key（未设时使用 OPENAI_API_KEY）
 *   WHISPER_BASE_URL    API 地址（默认 https://api.openai.com/v1）
 *   WHISPER_MODEL       模型名称（默认 whisper-1）
 *   WHISPER_LANGUAGE    语言提示，如 "zh"（默认空，自动检测）
 */

import { spawn } from 'child_process';
import fetch from 'node-fetch';
import FormData from 'form-data';

// 需要 ffmpeg 转码的格式
const NEEDS_CONVERSION = new Set(['ogg', 'opus', 'amr', 'silk', 'm4a', 'aac']);

/**
 * 转写音频为文字
 * @param {Buffer} audioBuffer  音频二进制数据
 * @param {string} format       格式（ogg/amr/mp3/m4a 等）
 * @returns {Promise<string>}   转写文字；空字符串表示未识别到语音内容；出错时抛出异常
 */
async function transcribeAudio(audioBuffer, format) {
  const srcFormat = (format || 'ogg').toLowerCase();
  let mp3Buffer = audioBuffer;
  if (NEEDS_CONVERSION.has(srcFormat)) {
    mp3Buffer = await convertToMp3(audioBuffer, srcFormat);
  }
  return await whisperTranscribe(mp3Buffer, 'mp3');
}

/**
 * 使用 ffmpeg 将音频转换为 mp3（16kHz 单声道）
 */
function convertToMp3(inputBuffer, srcFormat) {
  return new Promise((resolve, reject) => {
    // AMR 需要显式指定输入格式，OGG 可自动识别
    const args = srcFormat === 'amr'
      ? ['-f', 'amr', '-i', 'pipe:0', '-f', 'mp3', '-ac', '1', '-ar', '16000', '-y', 'pipe:1']
      : ['-i', 'pipe:0', '-f', 'mp3', '-ac', '1', '-ar', '16000', '-y', 'pipe:1'];

    const proc = spawn('ffmpeg', args, { stdio: ['pipe', 'pipe', 'pipe'] });
    const chunks = [];
    const errChunks = [];

    proc.stdout.on('data', chunk => chunks.push(chunk));
    proc.stderr.on('data', chunk => errChunks.push(chunk));

    proc.on('close', code => {
      if (code !== 0) {
        const errMsg = Buffer.concat(errChunks).toString().slice(-500);
        return reject(new Error(`ffmpeg exited ${code}: ${errMsg}`));
      }
      resolve(Buffer.concat(chunks));
    });

    proc.on('error', err => reject(new Error(`ffmpeg spawn failed: ${err.message}`)));

    proc.stdin.write(inputBuffer);
    proc.stdin.end();
  });
}

/**
 * 调用 Whisper API 转写 mp3 音频
 */
async function whisperTranscribe(audioBuffer, format) {
  const baseUrl = process.env.WHISPER_BASE_URL || 'https://api.openai.com/v1';
  const apiKey  = process.env.WHISPER_API_KEY  || process.env.OPENAI_API_KEY || '';
  const model   = process.env.WHISPER_MODEL    || 'whisper-1';
  const lang    = process.env.WHISPER_LANGUAGE || '';

  if (!apiKey) {
    throw new Error('Whisper API key not configured (set WHISPER_API_KEY or OPENAI_API_KEY)');
  }

  const form = new FormData();
  form.append('file', audioBuffer, {
    filename: `audio.${format}`,
    contentType: `audio/${format}`,
  });
  form.append('model', model);
  form.append('response_format', 'text');
  if (lang) form.append('language', lang);

  const resp = await fetch(`${baseUrl}/audio/transcriptions`, {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${apiKey}`,
      ...form.getHeaders(),
    },
    body: form,
  });

  if (!resp.ok) {
    const body = await resp.text().catch(() => '');
    throw new Error(`Whisper API ${resp.status}: ${body.slice(0, 200)}`);
  }

  return (await resp.text()).trim();
}

/**
 * 检查 ffmpeg 是否可用
 */
async function checkFfmpeg() {
  return new Promise(resolve => {
    const proc = spawn('ffmpeg', ['-version'], { stdio: 'ignore' });
    proc.on('error', () => resolve(false));
    proc.on('close', code => resolve(code === 0));
  });
}

export { transcribeAudio, checkFfmpeg };
