"""
素材库自动匹配 单元测试

覆盖：
- all 模式：返回全部 ready 视频素材 ID
- random 模式：随机选取 N 个
- smart 模式：按质量分/时长评分降序选取
- 无 ready 视频素材时返回空列表
- count=0 时返回全部（random/smart 模式）
- 非视频素材和非 ready 状态素材被过滤
"""

from __future__ import annotations

import sys
from pathlib import Path

sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "apps" / "api"))

from app.api.routes.generation_tasks import _select_assets_from_library

from packages.domain import Asset, AssetStatus


def _asset(
    id: str,
    name: str,
    mime_type: str = "video/mp4",
    status: AssetStatus = AssetStatus.READY,
    quality_score: float | None = None,
    duration: float | None = None,
) -> Asset:
    a = Asset.create(
        project_id="proj-1",
        library_id="lib-1",
        name=name,
        storage_key=f"uploads/{name}",
        mime_type=mime_type,
        file_size=1024,
        status=status,
        quality_score=quality_score,
        duration=duration,
    )
    # create() 会覆盖 id，手动设置
    a.id = id
    return a


class TestSelectAssetsAllMode:
    """all 模式：返回全部 ready 视频素材。"""

    def test_returns_all_ready_video_assets(self):
        assets = [
            _asset("a1", "v1.mp4"),
            _asset("a2", "v2.mp4"),
            _asset("a3", "v3.mp4"),
        ]
        result = _select_assets_from_library(assets, mode="all", count=0)
        assert sorted(result) == ["a1", "a2", "a3"]

    def test_ignores_count_in_all_mode(self):
        assets = [
            _asset("a1", "v1.mp4"),
            _asset("a2", "v2.mp4"),
        ]
        result = _select_assets_from_library(assets, mode="all", count=1)
        assert len(result) == 2

    def test_filters_non_video_assets(self):
        assets = [
            _asset("a1", "v1.mp4", mime_type="video/mp4"),
            _asset("a2", "img.jpg", mime_type="image/jpeg"),
            _asset("a3", "v2.mov", mime_type="video/quicktime"),
        ]
        result = _select_assets_from_library(assets, mode="all", count=0)
        assert sorted(result) == ["a1", "a3"]

    def test_filters_non_ready_assets(self):
        assets = [
            _asset("a1", "v1.mp4", status=AssetStatus.READY),
            _asset("a2", "v2.mp4", status=AssetStatus.UPLOADING),
            _asset("a3", "v3.mp4", status=AssetStatus.PROCESSING),
        ]
        result = _select_assets_from_library(assets, mode="all", count=0)
        assert result == ["a1"]

    def test_empty_library_returns_empty(self):
        result = _select_assets_from_library([], mode="all", count=0)
        assert result == []

    def test_no_ready_video_returns_empty(self):
        assets = [
            _asset("a1", "v1.mp4", status=AssetStatus.UPLOADING),
            _asset("a2", "img.jpg", mime_type="image/jpeg", status=AssetStatus.READY),
        ]
        result = _select_assets_from_library(assets, mode="all", count=0)
        assert result == []


class TestSelectAssetsRandomMode:
    """random 模式：随机选取 N 个。"""

    def test_random_selects_exact_count(self):
        assets = [_asset(f"a{i}", f"v{i}.mp4") for i in range(10)]
        result = _select_assets_from_library(assets, mode="random", count=3)
        assert len(result) == 3
        assert all(rid in [a.id for a in assets] for rid in result)

    def test_random_count_zero_returns_all(self):
        assets = [_asset(f"a{i}", f"v{i}.mp4") for i in range(5)]
        result = _select_assets_from_library(assets, mode="random", count=0)
        assert len(result) == 5

    def test_random_count_exceeds_total_returns_all(self):
        assets = [_asset(f"a{i}", f"v{i}.mp4") for i in range(3)]
        result = _select_assets_from_library(assets, mode="random", count=100)
        assert len(result) == 3


class TestSelectAssetsSmartMode:
    """smart 模式：按质量分/时长评分降序选取。"""

    def test_smart_sorts_by_quality_score_desc(self):
        assets = [
            _asset("low", "low.mp4", quality_score=0.3),
            _asset("high", "high.mp4", quality_score=0.9),
            _asset("mid", "mid.mp4", quality_score=0.6),
        ]
        result = _select_assets_from_library(assets, mode="smart", count=0)
        assert result == ["high", "mid", "low"]

    def test_smart_tiebreak_by_duration_desc(self):
        assets = [
            _asset("short", "short.mp4", quality_score=0.8, duration=10.0),
            _asset("long", "long.mp4", quality_score=0.8, duration=60.0),
        ]
        result = _select_assets_from_library(assets, mode="smart", count=0)
        assert result == ["long", "short"]

    def test_smart_with_count_limits_results(self):
        assets = [
            _asset("a1", "v1.mp4", quality_score=0.9),
            _asset("a2", "v2.mp4", quality_score=0.7),
            _asset("a3", "v3.mp4", quality_score=0.5),
        ]
        result = _select_assets_from_library(assets, mode="smart", count=2)
        assert result == ["a1", "a2"]

    def test_smart_null_quality_treated_as_zero(self):
        assets = [
            _asset("scored", "scored.mp4", quality_score=0.5),
            _asset("unscored", "unscored.mp4", quality_score=None),
        ]
        result = _select_assets_from_library(assets, mode="smart", count=0)
        assert result == ["scored", "unscored"]

    def test_smart_count_zero_returns_all_sorted(self):
        assets = [
            _asset("a1", "v1.mp4", quality_score=0.1),
            _asset("a2", "v2.mp4", quality_score=0.9),
            _asset("a3", "v3.mp4", quality_score=0.5),
        ]
        result = _select_assets_from_library(assets, mode="smart", count=0)
        assert result == ["a2", "a3", "a1"]


class TestSelectAssetsDefaultMode:
    """默认模式（未知 mode 字符串）应回退到 all。"""

    def test_unknown_mode_falls_back_to_all(self):
        assets = [
            _asset("a1", "v1.mp4"),
            _asset("a2", "v2.mp4"),
        ]
        result = _select_assets_from_library(assets, mode="unknown", count=0)
        assert len(result) == 2
