#!/usr/bin/env python3
"""
TTS Engine · Edge-TTS 配音引擎
==================================
为视频AI系统提供文本转语音能力，支持多角色音色配置。

依赖：
  pip install edge-tts

用法：
  # 基本用法（默认中文女声）
  python tts-engine.py --text "你好世界" --output output.mp3

  # 指定角色（从配置文件读取音色）
  python tts-engine.py --text "未来的天下第一宗！" --character "苏白" --output su-bai.mp3

  # 指定语音（Edge-TTS 语音名）
  python tts-engine.py --text "Hello World" --voice "en-US-JennyNeural" --output hello.mp3

  # 调整语速/音调/音量
  python tts-engine.py --text "你好" --rate "+20%" --pitch "+5Hz" --volume "+10%" --output output.mp3

  # 批量生成（从SRT字幕文件）
  python tts-engine.py --srt input.srt --output-dir ./audio/ --character "苏白"

  # 作为模块导入
  from tts_engine import generate_speech
  generate_speech("你好世界", "output.mp3", voice="zh-CN-XiaoxiaoNeural")

角色音色配置：
  video-ai-system/config/voices.json

路径：
  video-ai-system/engines/tts-engine.py
"""

import argparse
import asyncio
import json
import os
import sys
from pathlib import Path

try:
    import edge_tts
except ImportError:
    print("[ERROR] 缺少依赖：edge-tts")
    print("请先安装：pip install edge-tts")
    sys.exit(1)


# 默认角色音色配置
DEFAULT_VOICES = {
    "苏白": {
        "voice": "zh-CN-XiaoxiaoNeural",  # 阳光少年音
        "rate": "+5%",
        "pitch": "+0Hz"
    },
    "诸葛风": {
        "voice": "zh-CN-YunxiNeural",  # 沉稳男声
        "rate": "+0%",
        "pitch": "-5Hz"
    },
    "萧灵汐": {
        "voice": "zh-CN-XiaoyiNeural",  # 清冷女声
        "rate": "+0%",
        "pitch": "+0Hz"
    },
    "王执事": {
        "voice": "zh-CN-YunyangNeural",  # 中年男声
        "rate": "+0%",
        "pitch": "-10Hz"
    }
}


def load_voice_config(config_path: str = None) -> dict:
    """加载角色音色配置文件"""
    if config_path and os.path.isfile(config_path):
        try:
            with open(config_path, "r", encoding="utf-8") as f:
                return json.load(f)
        except Exception as e:
            print(f"[WARN] 无法读取配置文件 {config_path}：{e}")
            print("[INFO] 使用默认音色配置")
    return DEFAULT_VOICES


async def generate_speech_async(
    text: str,
    output_path: str,
    voice: str = "zh-CN-XiaoxiaoNeural",
    rate: str = "+0%",
    pitch: str = "+0Hz",
    volume: str = "+0%"
) -> bool:
    """
    异步生成语音（Edge-TTS）

    :param text: 要合成的文本
    :param output_path: 输出音频文件路径
    :param voice: Edge-TTS 语音名
    :param rate: 语速（如 "+20%"、"-10%"）
    :param pitch: 音调（如 "+5Hz"、"-10Hz"）
    :param volume: 音量（如 "+10%"、"-5%"）
    :return: 是否成功
    """
    try:
        # 确保输出目录存在
        os.makedirs(os.path.dirname(os.path.abspath(output_path)), exist_ok=True)

        communicate = edge_tts.Communicate(
            text, voice,
            rate=rate, pitch=pitch, volume=volume
        )
        await communicate.save(output_path)

        # 验证输出文件
        if os.path.isfile(output_path):
            file_size = os.path.getsize(output_path)
            print(f"[OK] 生成语音：{output_path} ({file_size // 1024} KB)")
            print(f"     语音：{voice} | 语速：{rate} | 音调：{pitch}")
            return True
        else:
            print(f"[ERROR] 输出文件未生成：{output_path}")
            return False

    except Exception as e:
        print(f"[ERROR] 生成语音失败：{e}")
        return False


def generate_speech(
    text: str,
    output_path: str,
    voice: str = "zh-CN-XiaoxiaoNeural",
    rate: str = "+0%",
    pitch: str = "+0Hz",
    volume: str = "+0%"
) -> bool:
    """
    同步包装器（供外部调用）

    :param text: 要合成的文本
    :param output_path: 输出音频文件路径
    :param voice: Edge-TTS 语音名
    :param rate: 语速
    :param pitch: 音调
    :param volume: 音量
    :return: 是否成功
    """
    return asyncio.run(generate_speech_async(text, output_path, voice, rate, pitch, volume))


def generate_by_character(
    text: str,
    output_path: str,
    character: str,
    config: dict = None
) -> bool:
    """
    按角色名生成语音（自动读取音色配置）

    :param text: 要合成的文本
    :param output_path: 输出音频文件路径
    :param character: 角色名（如 "苏白"）
    :param config: 音色配置字典（可选，默认加载 DEFAULT_VOICES）
    :return: 是否成功
    """
    if config is None:
        config = load_voice_config()

    if character not in config:
        print(f"[WARN] 角色 '{character}' 未配置音色，使用默认音色")
        return generate_speech(text, output_path)

    voice_config = config[character]
    return generate_speech(
        text, output_path,
        voice=voice_config.get("voice", "zh-CN-XiaoxiaoNeural"),
        rate=voice_config.get("rate", "+0%"),
        pitch=voice_config.get("pitch", "+0Hz")
    )


def process_srt(srt_path: str, output_dir: str, character: str = None, config: dict = None):
    """
    从SRT字幕文件批量生成语音

    :param srt_path: SRT 文件路径
    :param output_dir: 输出目录
    :param character: 角色名（所有台词用同一音色）
    :param config: 音色配置字典
    """
    if not os.path.isfile(srt_path):
        print(f"[ERROR] SRT 文件不存在：{srt_path}")
        return False

    os.makedirs(output_dir, exist_ok=True)

    # 简单SRT解析（按空行分割）
    with open(srt_path, "r", encoding="utf-8") as f:
        content = f.read()

    blocks = content.strip().split("\n\n")
    print(f"[INFO] 找到 {len(blocks)} 条字幕，开始生成语音...")

    success = 0
    for block in blocks:
        lines = block.strip().split("\n")
        if len(lines) < 3:
            continue

        idx = lines[0].strip()
        # timeine = lines[1].strip()  # 暂不使用时序
        text = " ".join(lines[2:]).strip()

        if not text:
            continue

        output_path = os.path.join(output_dir, f"{idx.zfill(4)}.mp3")

        if character:
            ok = generate_by_character(text, output_path, character, config)
        else:
            ok = generate_speech(text, output_path)

        if ok:
            success += 1

    print(f"\n[INFO] SRT批量生成完成：{success}/{len(blocks)} 成功")
    return success == len(blocks)


def list_voices():
    """列出所有可用的Edge-TTS语音"""
    print("[INFO] 正在获取可用语音列表...\n")
    asyncio.run(_list_voices_async())


async def _list_voices_async():
    """异步列出语音"""
    voices = await edge_tts.list_voices()
    print("中文语音：")
    for v in voices:
        if v["Locale"].startswith("zh-"):
            print(f"  {v['ShortName']:30s} - {v['FriendlyName']}")
    print(f"\n共 {len([v for v in voices if v['Locale'].startswith('zh-')])} 个中文语音")


def main():
    parser = argparse.ArgumentParser(
        description="TTS Engine · Edge-TTS 配音引擎",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
示例：
  python tts-engine.py --text "你好世界" --output output.mp3
  python tts-engine.py --text "未来的天下第一宗！" --character "苏白" --output su-bai.mp3
  python tts-engine.py --text "Hello" --voice "en-US-JennyNeural" --output hello.mp3
  python tts-engine.py --srt input.srt --output-dir ./audio/ --character "苏白"
  python tts-engine.py --list-voices
"""
    )
    parser.add_argument("--text", help="要合成的文本")
    parser.add_argument("--output", help="输出音频文件路径")
    parser.add_argument("--voice", default="zh-CN-XiaoxiaoNeural", help="Edge-TTS 语音名")
    parser.add_argument("--character", help="角色名（从配置文件读取音色）")
    parser.add_argument("--rate", default="+0%", help="语速（如 +20%%、-10%%）")
    parser.add_argument("--pitch", default="+0Hz", help="音调（如 +5Hz、-10Hz）")
    parser.add_argument("--volume", default="+0%", help="音量（如 +10%%、-5%%）")
    parser.add_argument("--srt", help="从SRT字幕文件批量生成")
    parser.add_argument("--output-dir", help="批量生成时的输出目录")
    parser.add_argument("--config", help="角色音色配置文件路径")
    parser.add_argument("--list-voices", action="store_true", help="列出所有可用语音")

    args = parser.parse_args()

    if args.list_voices:
        list_voices()
        sys.exit(0)

    if args.srt:
        # 批量模式
        if not args.output_dir:
            print("[ERROR] 批量模式需要指定 --output-dir")
            sys.exit(1)
        config = load_voice_config(args.config)
        ok = process_srt(args.srt, args.output_dir, args.character, config)
        sys.exit(0 if ok else 1)

    if not args.text or not args.output:
        print("[ERROR] 需要指定 --text 和 --output")
        parser.print_help()
        sys.exit(1)

    # 单文件模式
    if args.character:
        config = load_voice_config(args.config)
        ok = generate_by_character(args.text, args.output, args.character, config)
    else:
        ok = generate_speech(
            args.text, args.output,
            voice=args.voice, rate=args.rate,
            pitch=args.pitch, volume=args.volume
        )

    sys.exit(0 if ok else 1)


if __name__ == "__main__":
    main()
