"""TTS Job Use Cases 单元测试"""

from __future__ import annotations

from unittest.mock import MagicMock

import pytest

from packages.application.tts_job.exceptions import TTSJobNotFoundError
from packages.application.tts_job.use_cases import (
    CreateTTSJobUseCase,
    DeleteTTSJobUseCase,
    GetTTSJobStatusUseCase,
    GetTTSJobUseCase,
    ListTTSJobsUseCase,
)
from packages.domain.tts_job import TTSJob, TTSJobStatus


@pytest.fixture
def mock_repo():
    return MagicMock()


@pytest.fixture
def sample_job():
    return TTSJob.create(
        user_id="user_001",
        input_text="测试文本",
        voice_id="voice_001",
        voice_model="cosyvoice",
        project_id="proj_001",
        sample_rate=22050,
        format="mp3",
        max_retries=3,
    )


class TestCreateTTSJobUseCase:
    """创建 TTS 任务用例测试"""

    def test_create_success(self, mock_repo, sample_job):
        """创建成功"""
        mock_repo.create.return_value = sample_job

        use_case = CreateTTSJobUseCase(mock_repo)
        result = use_case.execute(
            user_id="user_001",
            input_text="测试文本",
            voice_id="voice_001",
            voice_model="cosyvoice",
            project_id="proj_001",
        )

        assert result is not None
        assert result.user_id == "user_001"
        assert result.input_text == "测试文本"
        assert result.status == TTSJobStatus.PENDING
        mock_repo.create.assert_called_once()

    def test_create_with_default_params(self, mock_repo):
        """使用默认参数创建"""
        mock_repo.create.side_effect = lambda x: x

        use_case = CreateTTSJobUseCase(mock_repo)
        result = use_case.execute(user_id="user_001", input_text="hello")

        assert result.voice_id == ""
        assert result.voice_model == ""
        assert result.sample_rate == 22050
        assert result.format == "mp3"
        assert result.max_retries == 3

    def test_create_with_metadata(self, mock_repo):
        """创建时携带 metadata"""
        mock_repo.create.side_effect = lambda x: x

        use_case = CreateTTSJobUseCase(mock_repo)
        result = use_case.execute(
            user_id="user_001",
            input_text="test",
            metadata={"source": "api", "priority": "high"},
        )

        assert result.metadata["source"] == "api"
        assert result.metadata["priority"] == "high"

    def test_create_with_voice_clone_profile(self, mock_repo):
        """使用音色克隆档案创建"""
        mock_repo.create.side_effect = lambda x: x

        use_case = CreateTTSJobUseCase(mock_repo)
        result = use_case.execute(
            user_id="user_001",
            input_text="test",
            voice_clone_profile_id="clone_001",
        )

        assert result.voice_clone_profile_id == "clone_001"


class TestListTTSJobsUseCase:
    """列出 TTS 任务用例测试"""

    def test_list_success(self, mock_repo, sample_job):
        """列出任务成功"""
        mock_repo.list_by_user.return_value = [sample_job]
        mock_repo.count_by_user.return_value = 1

        use_case = ListTTSJobsUseCase(mock_repo)
        items, total = use_case.execute(user_id="user_001")

        assert len(items) == 1
        assert total == 1
        mock_repo.list_by_user.assert_called_once_with("user_001", status=None, limit=50, offset=0)

    def test_list_with_status_filter(self, mock_repo):
        """按状态过滤"""
        mock_repo.list_by_user.return_value = []
        mock_repo.count_by_user.return_value = 0

        use_case = ListTTSJobsUseCase(mock_repo)
        items, total = use_case.execute(user_id="user_001", status="completed")

        assert total == 0
        mock_repo.list_by_user.assert_called_once_with("user_001", status="completed", limit=50, offset=0)
        mock_repo.count_by_user.assert_called_once_with("user_001", status="completed")

    def test_list_with_pagination(self, mock_repo):
        """分页参数正确传递"""
        mock_repo.list_by_user.return_value = []
        mock_repo.count_by_user.return_value = 0

        use_case = ListTTSJobsUseCase(mock_repo)
        use_case.execute(user_id="user_001", skip=10, limit=20)

        mock_repo.list_by_user.assert_called_once_with("user_001", status=None, limit=20, offset=10)

    def test_list_empty(self, mock_repo):
        """空列表"""
        mock_repo.list_by_user.return_value = []
        mock_repo.count_by_user.return_value = 0

        use_case = ListTTSJobsUseCase(mock_repo)
        items, total = use_case.execute(user_id="user_001")

        assert items == []
        assert total == 0


class TestGetTTSJobUseCase:
    """获取 TTS 任务详情用例测试"""

    def test_get_success(self, mock_repo, sample_job):
        """获取成功"""
        mock_repo.get.return_value = sample_job

        use_case = GetTTSJobUseCase(mock_repo)
        result = use_case.execute(job_id=sample_job.id, user_id="user_001")

        assert result.id == sample_job.id
        mock_repo.get.assert_called_once_with(sample_job.id)

    def test_get_not_found(self, mock_repo):
        """任务不存在"""
        mock_repo.get.return_value = None

        use_case = GetTTSJobUseCase(mock_repo)

        with pytest.raises(TTSJobNotFoundError):
            use_case.execute(job_id="nonexistent", user_id="user_001")

    def test_get_wrong_user(self, mock_repo, sample_job):
        """用户不匹配"""
        mock_repo.get.return_value = sample_job  # user_001

        use_case = GetTTSJobUseCase(mock_repo)

        with pytest.raises(TTSJobNotFoundError):
            use_case.execute(job_id=sample_job.id, user_id="other_user")


class TestGetTTSJobStatusUseCase:
    """查询 TTS 任务状态用例测试"""

    def test_get_status_success(self, mock_repo, sample_job):
        """获取状态成功"""
        mock_repo.get.return_value = sample_job

        use_case = GetTTSJobStatusUseCase(mock_repo)
        result = use_case.execute(job_id=sample_job.id, user_id="user_001")

        assert result.status == TTSJobStatus.PENDING

    def test_get_status_not_found(self, mock_repo):
        """任务不存在抛异常"""
        mock_repo.get.return_value = None

        use_case = GetTTSJobStatusUseCase(mock_repo)

        with pytest.raises(TTSJobNotFoundError):
            use_case.execute(job_id="nonexistent", user_id="user_001")

    def test_get_status_wrong_user(self, mock_repo, sample_job):
        """用户不匹配抛异常"""
        mock_repo.get.return_value = sample_job

        use_case = GetTTSJobStatusUseCase(mock_repo)

        with pytest.raises(TTSJobNotFoundError):
            use_case.execute(job_id=sample_job.id, user_id="other_user")


class TestDeleteTTSJobUseCase:
    """删除 TTS 任务用例测试"""

    def test_delete_success(self, mock_repo, sample_job):
        """删除成功"""
        mock_repo.get.return_value = sample_job
        mock_repo.delete.return_value = True

        use_case = DeleteTTSJobUseCase(mock_repo)
        result = use_case.execute(job_id=sample_job.id, user_id="user_001")

        assert result is True
        mock_repo.delete.assert_called_once_with(sample_job.id)

    def test_delete_not_found(self, mock_repo):
        """任务不存在返回 False"""
        mock_repo.get.return_value = None

        use_case = DeleteTTSJobUseCase(mock_repo)
        result = use_case.execute(job_id="nonexistent", user_id="user_001")

        assert result is False
        mock_repo.delete.assert_not_called()

    def test_delete_wrong_user(self, mock_repo, sample_job):
        """用户不匹配返回 False"""
        mock_repo.get.return_value = sample_job

        use_case = DeleteTTSJobUseCase(mock_repo)
        result = use_case.execute(job_id=sample_job.id, user_id="other_user")

        assert result is False
        mock_repo.delete.assert_not_called()
