#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
VOICE-EMOTION-COMPILER
语音情感编译器 — 把"苏白·大声·自信"转成 TTS 参数。

功能:
1. 情感标签解析 ("苏白·大声·自信" → rate/pitch/volume)
2. 支持 Edge-TTS 和豆包语音 A/B 测试
3. 生成 voice_profile.hdlp 供 Agent_04 读取
4. 批量生成不同情感参数的音频供 A/B 测试

用法:
  python voice-emotion-compiler.py --text "未来的天下第一宗！" --emotion "苏白·大声·自信" --output su-bai-loud.mp3
  python voice-emotion-compiler.py --ab-test --text "你好" --emotion "苏白·平静"
  python voice-emotion-compiler.py --generate-profile --character "苏白"
"""

import os
import sys
import json
import argparse
import importlib.util
from pathlib import Path
from datetime import datetime

PROJECT_ROOT = Path(__file__).parent.parent
sys.path.insert(0, str(PROJECT_ROOT / "engines"))

# 导入现有的 TTS 引擎。文件名是 tts-engine.py，不能用普通 import。
tts_engine_path = PROJECT_ROOT / "engines" / "tts-engine.py"
try:
    spec = importlib.util.spec_from_file_location("tts_engine", tts_engine_path)
    tts_engine = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(tts_engine)
    generate_speech = tts_engine.generate_speech
    generate_by_character = tts_engine.generate_by_character
    load_voice_config = tts_engine.load_voice_config
except Exception as exc:
    print(f"⚠️  无法导入 tts-engine，将使用简化模式: {exc}")
    generate_speech = None
    generate_by_character = None


class VoiceEmotionCompiler:
    """语音情感编译器"""

    # 情感映射表: "角色·情感·强度" → TTS 参数
    EMOTION_MAP = {
        # 苏白情感库
        "苏白·平静·正常": {
            "rate": "+0%",
            "pitch": "+0Hz",
            "volume": "+0%",
            "voice": "zh-CN-XiaoxiaoNeural",  # 阳光少年音
            "style": None,  # Edge-TTS 不支持 style，用参数模拟
        },
        "苏白·大声·自信": {
            "rate": "+20%",   # 语速加快
            "pitch": "+10Hz",  # 音调略高
            "volume": "+15%",  # 音量增加
            "voice": "zh-CN-XiaoxiaoNeural",
            "style": None,
        },
        "苏白·小声·犹豫": {
            "rate": "-15%",
            "pitch": "-5Hz",
            "volume": "-10%",
            "voice": "zh-CN-XiaoxiaoNeural",
            "style": None,
        },
        "苏白·生气·愤怒": {
            "rate": "+25%",
            "pitch": "+15Hz",
            "volume": "+20%",
            "voice": "zh-CN-XiaoxiaoNeural",
            "style": None,
        },
        "苏白·惊讶·震惊": {
            "rate": "+30%",
            "pitch": "+20Hz",
            "volume": "+10%",
            "voice": "zh-CN-XiaoxiaoNeural",
            "style": None,
        },
        "苏白·悲伤·失落": {
            "rate": "-20%",
            "pitch": "-10Hz",
            "volume": "-5%",
            "voice": "zh-CN-XiaoxiaoNeural",
            "style": None,
        },

        # 诸葛风情感库
        "诸葛风·平静·沉稳": {
            "rate": "+0%",
            "pitch": "-5Hz",
            "volume": "+0%",
            "voice": "zh-CN-YunxiNeural",  # 沉稳男声
            "style": None,
        },
        "诸葛风·大声·威严": {
            "rate": "+10%",
            "pitch": "-10Hz",  # 低沉有力
            "volume": "+20%",
            "voice": "zh-CN-YunxiNeural",
            "style": None,
        },

        # 萧灵汐情感库
        "萧灵汐·平静·清冷": {
            "rate": "+0%",
            "pitch": "+5Hz",
            "volume": "+0%",
            "voice": "zh-CN-XiaoyiNeural",  # 清冷女声
            "style": None,
        },
        "萧灵汐·大声·愤怒": {
            "rate": "+15%",
            "pitch": "+10Hz",
            "volume": "+15%",
            "voice": "zh-CN-XiaoyiNeural",
            "style": None,
        },
    }

    # 豆包语音情感映射 (如果豆包 API 支持情感参数)
    DOUBAO_EMOTION_MAP = {
        "苏白·平静·正常": {"emotion": "neutral", "speed": 1.0, "pitch": 1.0, "volume": 1.0},
        "苏白·大声·自信": {"emotion": "happy", "speed": 1.2, "pitch": 1.1, "volume": 1.15},
        "苏白·生气·愤怒": {"emotion": "angry", "speed": 1.25, "pitch": 1.15, "volume": 1.2},
        "苏白·惊讶·震惊": {"emotion": "surprised", "speed": 1.3, "pitch": 1.2, "volume": 1.1},
        "苏白·悲伤·失落": {"emotion": "sad", "speed": 0.8, "pitch": 0.9, "volume": 0.95},
    }

    def __init__(self, character=None):
        self.character = character
        self.voice_profiles = {}

    def parse_emotion_tag(self, emotion_tag):
        """
        解析情感标签
        格式: "角色·情感·强度" 或 "情感·强度"
        返回: TTS 参数字典
        """
        print(f"🔍 解析情感标签: {emotion_tag}")

        # 直接查找映射表
        if emotion_tag in self.EMOTION_MAP:
            params = self.EMOTION_MAP[emotion_tag].copy()
            print(f"  ✅ 找到映射: rate={params['rate']}, pitch={params['pitch']}, volume={params['volume']}")
            return params

        # 模糊匹配: 只给情感，不给角色
        for key, val in self.EMOTION_MAP.items():
            if emotion_tag in key:
                params = val.copy()
                print(f"  ⚠️  模糊匹配: {key} → rate={params['rate']}")
                return params

        # 未找到，使用默认
        print(f"  ⚠️  未找到映射，使用默认参数")
        return {
            "rate": "+0%",
            "pitch": "+0Hz",
            "volume": "+0%",
            "voice": "zh-CN-XiaoxiaoNeural",
            "style": None,
        }

    def compile_to_tts_params(self, emotion_tag, engine="edge-tts"):
        """
        将情感标签编译为 TTS 参数
        engine: "edge-tts" | "doubao"
        """
        if engine == "edge-tts":
            return self.parse_emotion_tag(emotion_tag)
        elif engine == "doubao":
            # 豆包语音参数
            if emotion_tag in self.DOUBAO_EMOTION_MAP:
                return self.DOUBAO_EMOTION_MAP[emotion_tag]
            else:
                return {"emotion": "neutral", "speed": 1.0, "pitch": 1.0, "volume": 1.0}
        else:
            raise ValueError(f"不支持的引擎: {engine}")

    def generate_speech_with_emotion(self, text, emotion_tag, output_path, engine="edge-tts"):
        """
        生成带情感的语音
        """
        print(f"\n🎤 生成情感语音")
        print(f"   文本: {text}")
        print(f"   情感: {emotion_tag}")
        print(f"   引擎: {engine}")

        params = self.compile_to_tts_params(emotion_tag, engine)

        if engine == "edge-tts":
            if generate_speech is None:
                print("  ❌ tts-engine 不可用")
                return False

            ok = generate_speech(
                text=text,
                output_path=output_path,
                voice=params["voice"],
                rate=params["rate"],
                pitch=params["pitch"],
                volume=params["volume"]
            )
            return ok

        elif engine == "doubao":
            # 豆包语音 API 调用
            print(f"  📤 调用豆包语音 API...")
            print(f"   参数: {params}")
            # TODO: 实现豆包 API 调用
            # doubao_api_call(text, output_path, params)
            print(f"  ⚠️  豆包 API 调用未实现")
            return False

        return False

    def ab_test(self, text, emotion_tag, output_dir):
        """
        A/B 测试: 生成不同参数的音频
        """
        print(f"\n🧪 A/B 测试: {emotion_tag}")
        print(f"   文本: {text}")

        output_dir = Path(output_dir)
        output_dir.mkdir(parents=True, exist_ok=True)

        results = []

        # 生成多个变体
        variants = self._generate_variants(emotion_tag)

        for i, variant_params in enumerate(variants):
            output_path = output_dir / f"ab-test-{i+1:03d}.mp3"
            print(f"\n  [{i+1}/{len(variants)}] {variant_params['label']}")

            if generate_speech:
                ok = generate_speech(
                    text=text,
                    output_path=str(output_path),
                    voice=variant_params["params"]["voice"],
                    rate=variant_params["params"]["rate"],
                    pitch=variant_params["params"]["pitch"],
                    volume=variant_params["params"]["volume"]
                )
                if ok:
                    results.append({
                        "label": variant_params["label"],
                        "path": str(output_path),
                        "params": variant_params["params"]
                    })

        # 生成 A/B 测试报告
        report_path = output_dir / "ab-test-report.json"
        with open(report_path, "w", encoding="utf-8") as f:
            json.dump({
                "emotion_tag": emotion_tag,
                "text": text,
                "variants": results,
                "generated_at": datetime.now().isoformat()
            }, f, ensure_ascii=False, indent=2)

        print(f"\n✅ A/B 测试完成，生成 {len(results)} 个变体")
        print(f"   报告: {report_path}")

        return results

    def _generate_variants(self, emotion_tag):
        """生成多个变体参数"""
        base_params = self.parse_emotion_tag(emotion_tag)

        variants = [
            {"label": "基准", "params": base_params},
            {"label": "语速+10%", "params": {**base_params, "rate": f"+{int(base_params['rate'].strip('%+')) + 10}%"}},
            {"label": "音调+5Hz", "params": {**base_params, "pitch": f"+{int(base_params['pitch'].strip('Hz+')) + 5}Hz"}},
            {"label": "音量+10%", "params": {**base_params, "volume": f"+{int(base_params['volume'].strip('%+')) + 10}%"}},
        ]

        return variants

    def generate_voice_profile(self, character):
        """
        生成角色的 voice_profile.hdlp
        保存到 assets/characters/<CHAR-ID>/voice/voice-profile.hdlp
        """
        print(f"\n📝 生成 {character} 的语音画像...")

        character_dir = PROJECT_ROOT / "assets" / "characters" / character
        voice_dir = character_dir / "voice"
        voice_dir.mkdir(parents=True, exist_ok=True)

        profile_path = voice_dir / "voice-profile.hdlp"

        # 收集该角色的所有情感
        character_prefix = character.replace("CHAR-", "").replace("-", "")
        # 简单匹配: 找所有以 "苏白" 开头的情感标签
        emotions = {}
        for key in self.EMOTION_MAP.keys():
            if key.startswith("苏白"):  # TODO: 根据实际角色名匹配
                emotions[key] = self.EMOTION_MAP[key]

        # 生成 HLDP 格式的配置
        profile_content = f"""# 语音画像 · {character}

> HLDP://video-ai-system/assets/characters/{character}/voice/voice-profile
> 类型: 语音配置 · 情感参数映射
> 建立: D144 · 2026-06-24
> 铸渊 ICE-GL-ZY001 · 冰朔 TCS-0002∞

---

## 默认音色

```
voice: {list(emotions.values())[0]['voice'] if emotions else 'zh-CN-XiaoxiaoNeural'}
engine: edge-tts
```

---

## 情感参数映射

"""

        for emotion_tag, params in emotions.items():
            profile_content += f"""### {emotion_tag}

```
rate: {params['rate']}
pitch: {params['pitch']}
volume: {params['volume']}
voice: {params['voice']}
```

"""

        profile_content += """---

## 使用方式

```
from voice_emotion_compiler import VoiceEmotionCompiler
compiler = VoiceEmotionCompiler()
params = compiler.compile_to_tts_params("苏白·大声·自信", engine="edge-tts")
generate_speech(text, output_path, **params)
```

---

⊢ 此文件由 VOICE-EMOTION-COMPILER 自动生成。
⊢ Agent_04 (配音) 读取此文件获取角色情感参数。
"""

        with open(profile_path, "w", encoding="utf-8") as f:
            f.write(profile_content)

        print(f"  ✅ 已生成: {profile_path}")
        return profile_path


def main():
    parser = argparse.ArgumentParser(description="VOICE-EMOTION-COMPILER")
    parser.add_argument("--text", type=str, help="要合成的文本")
    parser.add_argument("--emotion", type=str, help="情感标签 (如: '苏白·大声·自信')")
    parser.add_argument("--output", type=str, help="输出音频路径")
    parser.add_argument("--engine", type=str, default="edge-tts", choices=["edge-tts", "doubao"], help="TTS 引擎")
    parser.add_argument("--ab-test", action="store_true", help="A/B 测试模式")
    parser.add_argument("--output-dir", type=str, help="A/B 测试输出目录")
    parser.add_argument("--generate-profile", action="store_true", help="生成 voice_profile.hdlp")
    parser.add_argument("--character", type=str, help="角色ID")

    args = parser.parse_args()

    compiler = VoiceEmotionCompiler()

    if args.generate_profile:
        if not args.character:
            print("❌ --generate-profile 需要 --character")
            sys.exit(1)
        compiler.generate_voice_profile(args.character)
        sys.exit(0)

    if args.ab_test:
        if not args.text or not args.emotion or not args.output_dir:
            print("❌ --ab-test 需要 --text, --emotion, --output-dir")
            sys.exit(1)
        compiler.ab_test(args.text, args.emotion, args.output_dir)
        sys.exit(0)

    if not args.text or not args.emotion or not args.output:
        parser.print_help()
        sys.exit(1)

    ok = compiler.generate_speech_with_emotion(
        text=args.text,
        emotion_tag=args.emotion,
        output_path=args.output,
        engine=args.engine
    )

    sys.exit(0 if ok else 1)


if __name__ == "__main__":
    main()
