"""TTS Service Factory 单测 — TTS服务工厂."""

from __future__ import annotations

import os
from unittest.mock import patch

import pytest

# 注意：工厂模块有全局状态（_PROVIDERS），每个测试前重置
from services.tts_service_factory import (
    _PROVIDERS,
    available_providers,
    get_tts_service,
    register_provider,
)

# ── Fixtures ────────────────────────────────────────────────────────────────


@pytest.fixture(autouse=True)
def reset_providers():
    """每个测试前后重置 provider 注册表."""
    # 保存原始状态
    original = dict(_PROVIDERS)
    yield
    # 恢复
    _PROVIDERS.clear()
    _PROVIDERS.update(original)


# ── register_provider ──────────────────────────────────────────────────────


class TestRegisterProvider:
    """register_provider 注册供应商."""

    def test_register_new_provider(self):
        class DummyService:
            pass

        register_provider("dummy", DummyService)
        assert "dummy" in _PROVIDERS
        assert _PROVIDERS["dummy"] is DummyService

    def test_register_overwrites_existing(self):
        class ServiceV1:
            pass

        class ServiceV2:
            pass

        register_provider("test", ServiceV1)
        register_provider("test", ServiceV2)
        assert _PROVIDERS["test"] is ServiceV2


# ── get_tts_service ───────────────────────────────────────────────────────


class TestGetTtsService:
    """get_tts_service 获取TTS服务."""

    def test_get_mock_provider(self):
        """mock 供应商可用."""
        service = get_tts_service("mock")
        assert service is not None
        assert service.provider_name == "mock"

    def test_get_cosyvoice_provider(self):
        """cosyvoice 别名映射到 CosyVoiceTtsService."""
        # 不传 api_key 也能实例化（默认空字符串）
        service = get_tts_service("cosyvoice")
        assert service is not None
        assert service.provider_name == "cosyvoice"

    def test_aliyun_alias_maps_to_cosyvoice(self):
        """aliyun 是 cosyvoice 的别名."""
        service = get_tts_service("aliyun")
        assert service.provider_name == "cosyvoice"

    def test_dashscope_alias_maps_to_cosyvoice(self):
        """dashscope 是 cosyvoice 的别名."""
        service = get_tts_service("dashscope")
        assert service.provider_name == "cosyvoice"

    def test_unknown_provider_falls_back_to_mock(self):
        """未知供应商回退到 mock."""
        service = get_tts_service("unknown_provider_xyz")
        assert service.provider_name == "mock"

    def test_provider_name_case_insensitive(self):
        """供应商名称不区分大小写."""
        service = get_tts_service("MOCK")
        assert service.provider_name == "mock"

    def test_passes_kwargs_to_constructor(self):
        """kwargs 传递给服务构造函数."""
        # MockTtsService 接受 ffmpeg_bin 参数
        service = get_tts_service("mock", ffmpeg_bin="/custom/ffmpeg")
        assert service is not None

    def test_none_provider_reads_env_var(self):
        """provider=None 时从 TTS_PROVIDER 环境变量读取."""
        with patch.dict(os.environ, {"TTS_PROVIDER": "mock"}):
            service = get_tts_service(None)
            assert service.provider_name == "mock"

    def test_empty_env_falls_back_to_auto_detect(self):
        """环境变量为空时自动检测."""
        with patch.dict(os.environ, {"TTS_PROVIDER": ""}):
            # 没有 cosyvoice_api_key 时应该用 mock
            service = get_tts_service(None)
            assert service.provider_name == "mock"


# ── available_providers ────────────────────────────────────────────────────


class TestAvailableProviders:
    """available_providers 可用供应商列表."""

    def test_returns_list(self):
        result = available_providers()
        assert isinstance(result, list)
        assert len(result) >= 1  # 至少有 mock

    def test_mock_is_always_available(self):
        result = available_providers()
        assert "mock" in result

    def test_after_register_appears_in_list(self):
        class Dummy:
            pass

        register_provider("dummy_test", Dummy)
        result = available_providers()
        assert "dummy_test" in result
