"""素材库 UseCase 单元测试."""

from __future__ import annotations

from unittest.mock import MagicMock

import pytest

from packages.application.asset_libraries import (
    CreateAssetLibraryCommand,
    CreateAssetLibraryUseCase,
    ListAssetLibrariesUseCase,
)
from packages.domain import AssetLibrary, AssetLibraryKind


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


@pytest.fixture
def sample_library():
    lib = AssetLibrary.create(
        project_id="proj_456",
        name="测试视频库",
        kind=AssetLibraryKind.VIDEO,
    )
    lib.id = "lib_123"
    return lib


class TestListAssetLibrariesUseCase:
    """ListAssetLibrariesUseCase 测试"""

    def test_list_returns_repo_results(self, mock_repo, sample_library):
        """正常返回 repository 的查询结果"""
        mock_repo.find_by_project.return_value = [sample_library]
        use_case = ListAssetLibrariesUseCase(mock_repo)

        result = use_case.execute("proj_456")

        assert len(result) == 1
        assert result[0].id == "lib_123"
        mock_repo.find_by_project.assert_called_once_with("proj_456")

    def test_empty_project_raises_value_error(self, mock_repo):
        """空 project_id 抛出 ValueError"""
        use_case = ListAssetLibrariesUseCase(mock_repo)

        with pytest.raises(ValueError, match="project_id 不能为空"):
            use_case.execute("")

        mock_repo.find_by_project.assert_not_called()

    def test_whitespace_project_raises_value_error(self, mock_repo):
        """纯空格 project_id 也抛出 ValueError"""
        use_case = ListAssetLibrariesUseCase(mock_repo)

        with pytest.raises(ValueError, match="project_id 不能为空"):
            use_case.execute("   ")

        mock_repo.find_by_project.assert_not_called()

    def test_project_id_stripped_before_query(self, mock_repo, sample_library):
        """project_id 会被 strip 后再查询"""
        mock_repo.find_by_project.return_value = [sample_library]
        use_case = ListAssetLibrariesUseCase(mock_repo)

        use_case.execute("  proj_456  ")

        mock_repo.find_by_project.assert_called_once_with("proj_456")

    def test_empty_list(self, mock_repo):
        """项目没有素材库时返回空列表"""
        mock_repo.find_by_project.return_value = []
        use_case = ListAssetLibrariesUseCase(mock_repo)

        result = use_case.execute("proj_456")

        assert result == []


class TestCreateAssetLibraryUseCase:
    """CreateAssetLibraryUseCase 测试"""

    def test_create_success(self, mock_repo, sample_library):
        """创建成功返回 AssetLibrary"""
        mock_repo.create.return_value = sample_library
        use_case = CreateAssetLibraryUseCase(mock_repo)

        command = CreateAssetLibraryCommand(
            project_id="proj_456",
            name="新素材库",
            kind=AssetLibraryKind.IMAGE,
        )
        result = use_case.execute(command)

        assert result.id == "lib_123"
        mock_repo.create.assert_called_once()
        # 验证传入 repository 的是一个 AssetLibrary 对象
        created = mock_repo.create.call_args[0][0]
        assert isinstance(created, AssetLibrary)
        assert created.project_id == "proj_456"
        assert created.name == "新素材库"
        assert created.kind == AssetLibraryKind.IMAGE

    def test_create_with_video_kind(self, mock_repo):
        """创建视频类型素材库"""
        mock_repo.create.side_effect = lambda x: x
        use_case = CreateAssetLibraryUseCase(mock_repo)

        command = CreateAssetLibraryCommand(
            project_id="proj_1",
            name="视频库",
            kind=AssetLibraryKind.VIDEO,
        )
        result = use_case.execute(command)

        assert result.kind == AssetLibraryKind.VIDEO
        assert result.name == "视频库"

    def test_create_with_voice_kind(self, mock_repo):
        """创建音色类型素材库"""
        mock_repo.create.side_effect = lambda x: x
        use_case = CreateAssetLibraryUseCase(mock_repo)

        command = CreateAssetLibraryCommand(
            project_id="proj_1",
            name="音色库",
            kind=AssetLibraryKind.VOICE,
        )
        result = use_case.execute(command)

        assert result.kind == AssetLibraryKind.VOICE


class TestCreateAssetLibraryCommand:
    """CreateAssetLibraryCommand 数据类测试"""

    def test_command_fields(self):
        """命令对象字段正确"""
        cmd = CreateAssetLibraryCommand(
            project_id="proj_1",
            name="test",
            kind=AssetLibraryKind.VIDEO,
        )
        assert cmd.project_id == "proj_1"
        assert cmd.name == "test"
        assert cmd.kind == AssetLibraryKind.VIDEO

    def test_command_is_dataclass(self):
        """命令是 dataclass"""
        from dataclasses import is_dataclass

        assert is_dataclass(CreateAssetLibraryCommand)
