/**
 * Copyright (c) 2026 Tencent. All rights reserved.
 * Module:   TXRealtimeTTS @ TXLiteAVSDK
 */

import * as LiteavBase from '../liteav_base/liteav_module_entry';
import LiteAVSDKNative from 'libliteavsdk_voiceai.so';

/** 引擎模式（对应 TXRealtimeTTSMode）。 */
export enum TXRealtimeTTSMode {
  Online = 0,   // 纯在线（WebSocket/HTTP）
  Offline = 1,  // 纯离线（本地引擎，无网可用）
  Mix = 2,      // 混合：优先在线，弱网自动降级离线，恢复后回切
}

/** 错误码（亦作为 onCompleted 的 code）。 */
export enum TXRealtimeTTSError {
  Ok = 0,
  InvalidState = 1,   // 状态不允许（如已处于Started状态时再次Start）
  InvalidParam = 2,   // 配置字段非法
  InternalError = 3,   // 内部错误
}

/** 音频输出模式（对应 AudioOutputMode）。 */
export enum TXRealtimeTTSAudioOutputMode {
  PlaybackOnly = 0,         // 仅播放音频，不回调音频帧
  CallbackOnly = 1,         // 仅回调音频帧，不播放
  PlaybackAndCallback = 2,  // 既播放音频又回调音频帧
}

/** 在线/混合鉴权（online / mix 必填）。 */
export class TXRealtimeTTSOnlineCredential {
  appId?: string;    // 应用 appid
  userId?: string;   // 用户 id
  userSig?: string;  // 用户签名（服务端下发，避免密钥打包进客户端）
}

/** 离线/混合鉴权（offline / mix 必填）。 */
export class TXRealtimeTTSOfflineLicense {
  licenseUrl?: string;  // 离线授权文件下载/校验地址
  licenseKey?: string;  // 离线授权 key
}

/** 统一参数（必填项）；其余可选参数一律通过 callExperimentalAPI 设置 */
export class TXRealtimeTTSParams {
  mode: TXRealtimeTTSMode = TXRealtimeTTSMode.Online;  // 引擎模式：在线 / 离线 / 混合
  online: TXRealtimeTTSOnlineCredential = new TXRealtimeTTSOnlineCredential();    // mode=online/mix 必填
  offline: TXRealtimeTTSOfflineLicense = new TXRealtimeTTSOfflineLicense();      // mode=offline/mix 必填
  voiceName?: string;  // 音色（音色名，必填）
  audioOutputMode: TXRealtimeTTSAudioOutputMode = TXRealtimeTTSAudioOutputMode.PlaybackOnly;  // 音频输出模式：仅播放 / 仅回调 / 播放并回调（默认 PlaybackOnly）
}

/** 音频输出帧（onSynthesizedAudioFrame 回调参数） */
export class TXSynthesizeAudioFrame {
  pcmData?: Uint8Array;     // 本次音频 PCM 字节；数据仅在回调内有效，跨线程/异步使用须深拷贝（如 slice()）
  pcmDataSize: number = 0;   // pcmData 字节数
  sampleRate: number = 16000;  // 音频采样率（Hz），如 16000/48000
  channelCount: number = 1;    // 音频通道数，1=单声道，2=双声道
  bitWidth: number = 16;     // 采样位宽（bit），固定 16
  textId?: string;       // 文本标识（对应 appendText 的 textId，标示本次数据所属的文本段）
  textSlice?: string;    // 当前合成的数据所属的文本片段
  progress: number = 0; // textSlice 在 textId 对应文本段中的百分比 [0.0, 1.0]
}

/** 回调监听器（所有回调均已切换到 UI 线程触发，调用方无需关心线程安全）。所有方法均为可选，按需实现即可 */
export interface ITXRealtimeTTSListener {
  /** 合成开始（鉴权通过 / 会话已建立），可在此切换 UI 状态 */
  onStarted?(): void;

  /**
   * 文本播放进度回调：逐片回调（流式）。
   * @param textId 当前文本段标识
   * @param textSlice 正在播放的文本切片
   */
  onPlaybackProgress?(textId: string, textSlice: string): void;

  /**
   * 合成进度回调。仅当 audioOutputMode 为 CallbackOnly 或 PlaybackAndCallback 时触发。
   * @param audioFrame 本次合成的音频帧（TXSynthesizeAudioFrame）
   */
  onSynthesizedAudioFrame?(audioFrame: TXSynthesizeAudioFrame): void;
  
  /**
   * 合成结束（成功或失败）
   * @param code - code == TXRealtimeTTSError.Ok 表示成功完成；否则表示任意阶段失败（鉴权失败 / 弱网 / 内部错误等）
   * @param msg - 错误信息（仅回调期间有效，可为 null）
   */
  onCompleted?(code: number, msg: string | null): void;
}

/**
 * 实时语音合成引擎：ArkTS 公共 API。
 * 实现由底层 NAPI 提供，构造函数内完成原生资源分配。
 */
export class TXRealtimeTTS {
  private nativeInstance: any;
  private listeners: ITXRealtimeTTSListener[] = [];

  constructor() {
    LiteavBase.initialize(null);
    this.nativeInstance = new LiteAVSDKNative.TXRealtimeTTSNapi();

    // 设置内部回调代理, fan-out 到所有 listener
    this.nativeInstance.setListener({
      onStarted: () => {
        this.listeners.forEach(l => l.onStarted?.());
      },
      onPlaybackProgress: (textId: string, textSlice: string) => {
        this.listeners.forEach(l => l.onPlaybackProgress?.(textId, textSlice));
      },
      onSynthesizedAudioFrame: (audioFrame: TXSynthesizeAudioFrame) => {
        this.listeners.forEach(l => l.onSynthesizedAudioFrame?.(audioFrame));
      },
      onCompleted: (code: number, msg: string | null) => {
        this.listeners.forEach(l => l.onCompleted?.(code, msg));
      }
    });
  }

  /**
   * 添加回调监听器。
   * @param listener 事件回调监听器（ITXRealtimeTTSListener 实现）
   */
  addListener(listener: ITXRealtimeTTSListener): void {
    this.listeners.push(listener);
  }

  /**
   * 移除回调监听器。
   * @param listener 之前通过 addListener 添加的监听器
   */
  removeListener(listener: ITXRealtimeTTSListener): void {
    const idx = this.listeners.indexOf(listener);
    if (idx >= 0) {
      this.listeners.splice(idx, 1);
    }
  }

  /**
   * 开始合成。
   * @param param 配置参数（TXRealtimeTTSParams）
   * @returns 返回 TXRealtimeTTSError 中的值
   */
  start(param: TXRealtimeTTSParams): number {
    return this.nativeInstance.start(param);
  }

  /**
   * 停止合成。
   * @returns 返回 TXRealtimeTTSError 中的值
   */
  stop(): number {
    return this.nativeInstance.stop();
  }

  /**
   * 暂停合成与播放。
   * @returns 返回 TXRealtimeTTSError 中的值
   */
  pause(): number {
    return this.nativeInstance.pause();
  }

  /**
   * 恢复合成与播放（对应 resume）。
   * @returns 返回 TXRealtimeTTSError 中的值
   */
  resume(): number {
    return this.nativeInstance.resume();
  }

  /**
   * 清空当前待播放与待合成的文本数据。
   * 调用 clear 之后，SDK 内部会立即丢弃所有排队文本，且保证不会再触发任何属于 clear 前 textId 的进度回调。
   * @returns 返回 TXRealtimeTTSError 中的值
   */
  clear(): number {
    return this.nativeInstance.clear();
  }

  /**
   * 追加待合成文本（流式输入）。
   * @param textId 文本标识（UTF-8，用于标识本次追加的文本）
   * @param text 文本内容（UTF-8，必填）
   * @param isEnd 是否为本段文本的最后一片，true 表示文本输入结束（默认 false）
   * @returns 返回 TXRealtimeTTSError 中的值
   */
  appendText(textId: string, text: string, isEnd: boolean = false): number {
    return this.nativeInstance.appendText(textId, text, isEnd);
  }

  /**
   * 设置音量。
   * @param volume 音量值，取值范围 [0, 200]，默认 100 = 正常
   * @returns 返回 TXRealtimeTTSError 中的值
   */
  setVolume(volume: number): number {
    return this.nativeInstance.setVolume(volume);
  }

  /**
   * 设置语速。
   * @param speed 语速值，取值范围 [1, 3]，默认 1 = 正常
   * @returns 返回 TXRealtimeTTSError 中的值
   */
  setSpeed(speed: number): number {
    return this.nativeInstance.setSpeed(speed);
  }

  /**
   * 实验性 API 调用接口。
   * @param jsonParams JSON 格式的参数字符串
   * @returns JSON 格式的返回结果
   */
  callExperimentalAPI(jsonParams: string): string | null {
    return this.nativeInstance.callExperimentalAPI(jsonParams);
  }
}
