import { BadRequestException, Injectable, Logger, ServiceUnavailableException } from '@nestjs/common';

export interface TranscribeResult {
  text: string;
  durationSec?: number;
}

/**
 * TranscribeService — 语音听写转文字(provider 可切换;现仅 sensevoice)。
 *
 * sensevoice = 自部署 SenseVoice-small 容器(apps/asr-sensevoice,内网 HTTP)。
 * 选它的原因:患者语音可能含姓名/手机号(医疗 PII)→ 不出内网;零按量费;CPU 即可。
 * 以后要换云 ASR(火山/讯飞)→ 加 provider 分支 + 环境变量切换,前后端契约不变。
 */
@Injectable()
export class TranscribeService {
  private readonly logger = new Logger(TranscribeService.name);
  // compose 内走服务名 pac-asr;本地裸跑 node 时用发布到宿主的端口
  private readonly url = process.env.PAC_ASR_URL ?? 'http://127.0.0.1:8008';

  async transcribe(buf: Buffer, filename: string, mimetype: string): Promise<TranscribeResult> {
    if (!buf?.length) throw new BadRequestException('empty audio');

    const form = new FormData();
    form.append('file', new Blob([new Uint8Array(buf)], { type: mimetype || 'audio/webm' }), filename || 'audio.webm');

    let res: Response;
    try {
      res = await fetch(`${this.url}/transcribe`, {
        method: 'POST',
        body: form,
        signal: AbortSignal.timeout(60_000),
      });
    } catch (err) {
      this.logger.error(`ASR 服务不可达(${this.url}): ${err instanceof Error ? err.message : String(err)}`);
      throw new ServiceUnavailableException('语音识别服务暂不可用');
    }
    if (!res.ok) {
      const text = await res.text();
      this.logger.warn(`ASR ${res.status}: ${text.slice(0, 200)}`);
      if (res.status === 400 || res.status === 413) throw new BadRequestException('音频无法识别(格式/大小)');
      throw new ServiceUnavailableException('语音识别失败');
    }
    return (await res.json()) as TranscribeResult;
  }
}
