"""Assets UseCase 单元测试."""

from __future__ import annotations

from unittest.mock import MagicMock

import pytest

from packages.application.assets import (
    CreateAssetCommand,
    CreateAssetUseCase,
    ListAssetsUseCase,
)
from packages.domain import Asset, AssetStatus, ClassificationStatus


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


@pytest.fixture
def sample_asset():
    asset = Asset.create(
        project_id="proj_001",
        library_id="lib_001",
        name="test_video.mp4",
        storage_key="videos/test.mp4",
        mime_type="video/mp4",
        file_size=1024000,
        duration=15.5,
        width=1920,
        height=1080,
    )
    asset.id = "asset_001"
    return asset


class TestListAssetsUseCase:
    """ListAssetsUseCase 测试"""

    def test_list_returns_repo_results(self, mock_asset_repo, sample_asset):
        """正常返回 repository 的查询结果"""
        mock_asset_repo.find_by_library.return_value = [sample_asset]
        use_case = ListAssetsUseCase(mock_asset_repo)

        result = use_case.execute("lib_001")

        assert len(result) == 1
        assert result[0].id == "asset_001"
        mock_asset_repo.find_by_library.assert_called_once_with("lib_001")

    def test_empty_library_id_raises_value_error(self, mock_asset_repo):
        """空 library_id 抛出 ValueError"""
        use_case = ListAssetsUseCase(mock_asset_repo)

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

        mock_asset_repo.find_by_library.assert_not_called()

    def test_whitespace_library_id_raises_value_error(self, mock_asset_repo):
        """纯空格 library_id 抛出 ValueError"""
        use_case = ListAssetsUseCase(mock_asset_repo)

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

        mock_asset_repo.find_by_library.assert_not_called()

    def test_library_id_stripped_before_query(self, mock_asset_repo, sample_asset):
        """library_id 会被 strip 后再查询"""
        mock_asset_repo.find_by_library.return_value = [sample_asset]
        use_case = ListAssetsUseCase(mock_asset_repo)

        use_case.execute("  lib_001  ")

        mock_asset_repo.find_by_library.assert_called_once_with("lib_001")

    def test_empty_list(self, mock_asset_repo):
        """素材库为空时返回空列表"""
        mock_asset_repo.find_by_library.return_value = []
        use_case = ListAssetsUseCase(mock_asset_repo)

        result = use_case.execute("lib_001")

        assert result == []
        mock_asset_repo.find_by_library.assert_called_once_with("lib_001")


class TestCreateAssetUseCase:
    """CreateAssetUseCase 测试"""

    def test_create_asset_success(self, mock_asset_repo):
        """正常创建素材"""
        mock_asset_repo.create.side_effect = lambda a: a
        use_case = CreateAssetUseCase(mock_asset_repo)

        command = CreateAssetCommand(
            project_id="proj_001",
            library_id="lib_001",
            name="test.png",
            storage_key="images/test.png",
            mime_type="image/png",
            file_size=512000,
        )
        result = use_case.execute(command)

        assert result.name == "test.png"
        assert result.library_id == "lib_001"
        assert result.mime_type == "image/png"
        assert result.status == AssetStatus.UPLOADING
        assert result.classification_status == ClassificationStatus.PENDING
        mock_asset_repo.create.assert_called_once()

    def test_create_asset_with_metadata(self, mock_asset_repo):
        """创建带 metadata 的素材"""
        mock_asset_repo.create.side_effect = lambda a: a
        use_case = CreateAssetUseCase(mock_asset_repo)

        command = CreateAssetCommand(
            project_id="proj_001",
            library_id="lib_001",
            name="test.mp3",
            storage_key="audio/test.mp3",
            mime_type="audio/mpeg",
            metadata={"bitrate": 320, "sample_rate": 44100},
            duration=180.0,
        )
        result = use_case.execute(command)

        assert result.metadata["bitrate"] == 320
        assert result.duration == 180.0

    def test_create_asset_with_quality_score(self, mock_asset_repo):
        """创建带质量分的素材"""
        mock_asset_repo.create.side_effect = lambda a: a
        use_case = CreateAssetUseCase(mock_asset_repo)

        command = CreateAssetCommand(
            project_id="proj_001",
            library_id="lib_001",
            name="high_quality.mp4",
            storage_key="videos/hq.mp4",
            mime_type="video/mp4",
            quality_score=95.5,
            uploaded_by_user_id="user_001",
        )
        result = use_case.execute(command)

        assert result.quality_score == 95.5
        assert result.uploaded_by_user_id == "user_001"

    def test_create_asset_custom_status(self, mock_asset_repo):
        """创建时指定自定义状态"""
        mock_asset_repo.create.side_effect = lambda a: a
        use_case = CreateAssetUseCase(mock_asset_repo)

        command = CreateAssetCommand(
            project_id="proj_001",
            library_id="lib_001",
            name="ready.mp4",
            storage_key="videos/ready.mp4",
            mime_type="video/mp4",
            status=AssetStatus.READY,
            classification_status=ClassificationStatus.COMPLETED,
        )
        result = use_case.execute(command)

        assert result.status == AssetStatus.READY
        assert result.classification_status == ClassificationStatus.COMPLETED

    def test_create_asset_with_video_info(self, mock_asset_repo):
        """创建带视频参数的素材"""
        mock_asset_repo.create.side_effect = lambda a: a
        use_case = CreateAssetUseCase(mock_asset_repo)

        command = CreateAssetCommand(
            project_id="proj_001",
            library_id="lib_001",
            name="video.mp4",
            storage_key="videos/v.mp4",
            mime_type="video/mp4",
            width=1920,
            height=1080,
            fps=30.0,
            codec="h264",
            duration=60.0,
            thumbnail_url="https://cdn.example.com/thumb.jpg",
        )
        result = use_case.execute(command)

        assert result.width == 1920
        assert result.height == 1080
        assert result.fps == 30.0
        assert result.codec == "h264"
        assert result.thumbnail_url == "https://cdn.example.com/thumb.jpg"
