"""预置音色配置单元测试 — Phase 3 CosyVoice 集成."""

from __future__ import annotations

import pytest

from packages.domain.preset_voices import (
    PRESET_VOICES,
    PresetVoice,
    get_preset_voice_by_id,
    get_preset_voices,
    is_preset_voice,
)


class TestPresetVoice:
    """测试 PresetVoice 数据类。"""

    def test_preset_voice_fields(self) -> None:
        """预置音色字段完整。"""
        voice = PresetVoice(
            voice_id="test_voice",
            name="测试音色",
            description="测试描述",
            gender="female",
            language="zh-CN",
            preview_url="https://example.com/preview.mp3",
            tags=["测试"],
        )

        assert voice.voice_id == "test_voice"
        assert voice.name == "测试音色"
        assert voice.description == "测试描述"
        assert voice.gender == "female"
        assert voice.language == "zh-CN"
        assert voice.preview_url == "https://example.com/preview.mp3"
        assert voice.tags == ["测试"]

    def test_preset_voice_defaults(self) -> None:
        """预置音色默认值。"""
        voice = PresetVoice(
            voice_id="test",
            name="测试",
            description="描述",
            gender="male",
        )

        assert voice.language == "zh-CN"
        assert voice.preview_url == ""
        assert voice.tags is None

    def test_preset_voice_frozen(self) -> None:
        """预置音色不可变。"""
        voice = PresetVoice(
            voice_id="test",
            name="测试",
            description="描述",
            gender="male",
        )

        with pytest.raises(AttributeError):
            voice.name = "新名称"

    def test_preset_voice_to_dict(self) -> None:
        """序列化。"""
        voice = PresetVoice(
            voice_id="longxiaochun_v3",
            name="龙小淳",
            description="温柔女声",
            gender="female",
            tags=["温柔", "女声"],
        )

        result = voice.to_dict()

        assert result["voice_id"] == "longxiaochun_v3"
        assert result["name"] == "龙小淳"
        assert result["description"] == "温柔女声"
        assert result["gender"] == "female"
        assert result["language"] == "zh-CN"
        assert result["preview_url"] == ""
        assert result["tags"] == ["温柔", "女声"]

    def test_preset_voice_to_dict_no_tags(self) -> None:
        """tags 为 None 时序列化为空列表。"""
        voice = PresetVoice(
            voice_id="test",
            name="测试",
            description="描述",
            gender="male",
        )

        result = voice.to_dict()
        assert result["tags"] == []


class TestPresetVoicesConfig:
    """测试预置音色配置列表。"""

    def test_preset_voices_not_empty(self) -> None:
        """预置音色列表不为空。"""
        assert len(PRESET_VOICES) >= 5

    def test_preset_voices_has_8_voices(self) -> None:
        """应有 8 个预置音色。"""
        assert len(PRESET_VOICES) == 8

    def test_all_voices_have_required_fields(self) -> None:
        """所有预置音色都有必填字段。"""
        for voice in PRESET_VOICES:
            assert voice.voice_id, f"voice_id 为空: {voice}"
            assert voice.name, f"name 为空: {voice}"
            assert voice.description, f"description 为空: {voice}"
            assert voice.gender in ("male", "female"), f"gender 无效: {voice}"
            assert voice.language == "zh-CN", f"language 应为 zh-CN: {voice}"

    def test_all_voices_have_unique_ids(self) -> None:
        """所有预置音色 ID 唯一。"""
        ids = [v.voice_id for v in PRESET_VOICES]
        assert len(ids) == len(set(ids)), "存在重复的 voice_id"

    def test_all_voices_have_unique_names(self) -> None:
        """所有预置音色名称唯一。"""
        names = [v.name for v in PRESET_VOICES]
        assert len(names) == len(set(names)), "存在重复的 name"

    def test_cosyvoice_voice_ids(self) -> None:
        """音色 ID 应为 CosyVoice 真实可用的音色名。"""
        expected_ids = {
            "longxiaochun_v3",
            "longxiaoxia_v3",
            "longsanshu_v3",
            "longyue_v3",
            "longshu_v3",
            "longyingjing_v3",
            "longshuo_v3",
            "longtian_v3",
        }
        actual_ids = {v.voice_id for v in PRESET_VOICES}
        assert actual_ids == expected_ids

    def test_gender_distribution(self) -> None:
        """男女音色分布合理。"""
        male_count = sum(1 for v in PRESET_VOICES if v.gender == "male")
        female_count = sum(1 for v in PRESET_VOICES if v.gender == "female")
        assert male_count == 3
        assert female_count == 5

    def test_all_have_tags(self) -> None:
        """所有预置音色都有标签。"""
        for voice in PRESET_VOICES:
            assert voice.tags is not None, f"tags 为 None: {voice.name}"
            assert len(voice.tags) >= 2, f"标签太少: {voice.name}"


class TestPresetVoiceHelpers:
    """测试辅助函数。"""

    def test_get_preset_voices(self) -> None:
        """get_preset_voices 返回完整列表。"""
        voices = get_preset_voices()
        assert voices == PRESET_VOICES
        assert len(voices) == 8

    def test_get_preset_voice_by_id_found(self) -> None:
        """按 ID 查找存在的音色。"""
        voice = get_preset_voice_by_id("longxiaochun_v3")
        assert voice is not None
        assert voice.name == "龙小淳"
        assert voice.voice_id == "longxiaochun_v3"

    def test_get_preset_voice_by_id_not_found(self) -> None:
        """按 ID 查找不存在的音色。"""
        voice = get_preset_voice_by_id("nonexistent_voice")
        assert voice is None

    def test_is_preset_voice_true(self) -> None:
        """判断预置音色返回 True。"""
        assert is_preset_voice("longxiaochun_v3") is True
        assert is_preset_voice("longxiaoxia_v3") is True
        assert is_preset_voice("longshuo_v3") is True

    def test_is_preset_voice_false(self) -> None:
        """判断非预置音色返回 False。"""
        assert is_preset_voice("nonexistent") is False
        assert is_preset_voice("") is False
        assert is_preset_voice("user_custom_voice") is False
