"""自动选素材逻辑单元测试 — 过滤不支持的编码格式."""

from __future__ import annotations

import sys
from pathlib import Path
from unittest.mock import MagicMock

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

import pytest

from packages.domain import Asset, AssetLibrary, AssetLibraryKind, AssetStatus


def _make_asset(
    asset_id: str,
    *,
    status=AssetStatus.READY,
    mime_type: str = "video/mp4",
    codec: str | None = None,
    metadata: dict | None = None,
    width: int = 1080,
    height: int = 1920,
    created_at=None,
) -> Asset:
    """构造测试用 Asset 对象."""
    from datetime import datetime, timezone

    return Asset(
        id=asset_id,
        project_id="proj-1",
        library_id="lib-video",
        name=f"{asset_id}.mp4",
        storage_key=f"uploads/{asset_id}.mp4",
        mime_type=mime_type,
        status=status,
        codec=codec,
        metadata=metadata or {},
        width=width,
        height=height,
        created_at=created_at or datetime.now(timezone.utc),
    )


def _make_mock_repo(assets: list[Asset]):
    """构造 mock asset_repo."""
    mock_repo = MagicMock()
    mock_repo.find_by_library.return_value = assets
    return mock_repo


def _make_mock_lib_repo():
    """构造 mock asset_library_repo，返回一个视频素材库."""
    video_lib = AssetLibrary(
        id="lib-video",
        project_id="proj-1",
        name="视频",
        kind=AssetLibraryKind.VIDEO,
    )
    mock_repo = MagicMock()
    mock_repo.find_by_project.return_value = [video_lib]
    return mock_repo


class TestAutoSelectVideoAssetsCodecFilter:
    """自动选素材 — 编码格式不再过滤，渲染引擎统一转码."""

    def test_h264_assets_selected(self):
        """H.264 编码素材 → 正常选中."""
        from app.api.routes._helpers import auto_select_video_assets

        assets = [
            _make_asset("a1", codec="h264"),
            _make_asset("a2", codec="h264"),
        ]
        asset_repo = _make_mock_repo(assets)
        lib_repo = _make_mock_lib_repo()

        result = auto_select_video_assets(
            project_id="proj-1",
            asset_library_repo=lib_repo,
            asset_repo=asset_repo,
        )

        assert len(result) == 2
        assert "a1" in result
        assert "a2" in result

    def test_hevc_assets_not_filtered_by_codec_field(self):
        """HEVC 编码素材 → 不再被过滤，渲染引擎会统一转码."""
        from app.api.routes._helpers import auto_select_video_assets

        assets = [
            _make_asset("a1", codec="h264"),
            _make_asset("a2", codec="hevc"),
            _make_asset("a3", codec="h265"),
        ]
        asset_repo = _make_mock_repo(assets)
        lib_repo = _make_mock_lib_repo()

        result = auto_select_video_assets(
            project_id="proj-1",
            asset_library_repo=lib_repo,
            asset_repo=asset_repo,
        )

        # 所有编码的素材都保留，不再按编码过滤
        assert len(result) == 3
        assert "a1" in result
        assert "a2" in result
        assert "a3" in result

    def test_hevc_assets_not_filtered_by_metadata(self):
        """HEVC 编码素材（metadata 里有） → 不再被过滤."""
        from app.api.routes._helpers import auto_select_video_assets

        assets = [
            _make_asset("a1", codec=None, metadata={"codec": "h264"}),
            _make_asset("a2", codec=None, metadata={"codec": "hevc"}),
            _make_asset("a3", codec=None, metadata={"codec": "vp9"}),
        ]
        asset_repo = _make_mock_repo(assets)
        lib_repo = _make_mock_lib_repo()

        result = auto_select_video_assets(
            project_id="proj-1",
            asset_library_repo=lib_repo,
            asset_repo=asset_repo,
        )

        # 所有编码的素材都保留
        assert len(result) == 3

    def test_codec_field_takes_precedence_over_metadata(self):
        """codec 字段优先于 metadata 里的 codec."""
        from app.api.routes._helpers import auto_select_video_assets

        # codec 字段是 h264，但 metadata 里是 hevc → 不影响，都能选中
        assets = [
            _make_asset("a1", codec="h264", metadata={"codec": "hevc"}),
        ]
        asset_repo = _make_mock_repo(assets)
        lib_repo = _make_mock_lib_repo()

        result = auto_select_video_assets(
            project_id="proj-1",
            asset_library_repo=lib_repo,
            asset_repo=asset_repo,
        )

        assert len(result) == 1
        assert result[0] == "a1"

    def test_vp9_av1_assets_not_filtered(self):
        """VP9 / AV1 编码素材 → 不再被过滤，渲染引擎会统一转码."""
        from app.api.routes._helpers import auto_select_video_assets

        assets = [
            _make_asset("a1", codec="vp9"),
            _make_asset("a2", codec="av1"),
            _make_asset("a3", codec="h264"),
        ]
        asset_repo = _make_mock_repo(assets)
        lib_repo = _make_mock_lib_repo()

        result = auto_select_video_assets(
            project_id="proj-1",
            asset_library_repo=lib_repo,
            asset_repo=asset_repo,
        )

        # 所有编码的素材都保留
        assert len(result) == 3
        assert "a1" in result
        assert "a2" in result
        assert "a3" in result

    def test_missing_codec_kept(self):
        """codec 字段和 metadata 里都没有 → 暂时放过（兼容存量数据）."""
        from app.api.routes._helpers import auto_select_video_assets

        assets = [
            _make_asset("a1", codec=None, metadata={}),
            _make_asset("a2", codec="h264"),
        ]
        asset_repo = _make_mock_repo(assets)
        lib_repo = _make_mock_lib_repo()

        result = auto_select_video_assets(
            project_id="proj-1",
            asset_library_repo=lib_repo,
            asset_repo=asset_repo,
        )

        assert len(result) == 2

    def test_codec_case_insensitive(self):
        """不同编码格式的素材都保留，不再按编码过滤."""
        from app.api.routes._helpers import auto_select_video_assets

        assets = [
            _make_asset("a1", codec="HEVC"),
            _make_asset("a2", codec="H264"),
        ]
        asset_repo = _make_mock_repo(assets)
        lib_repo = _make_mock_lib_repo()

        result = auto_select_video_assets(
            project_id="proj-1",
            asset_library_repo=lib_repo,
            asset_repo=asset_repo,
        )

        # 所有编码的素材都保留
        assert len(result) == 2
        assert "a1" in result
        assert "a2" in result

    def test_only_ready_assets_selected(self):
        """只有 READY 状态的素材才会被选中."""
        from app.api.routes._helpers import auto_select_video_assets

        assets = [
            _make_asset("a1", status=AssetStatus.READY, codec="h264"),
            _make_asset("a2", status=AssetStatus.PROCESSING, codec="h264"),
            _make_asset("a3", status=AssetStatus.ERROR, codec="h264"),
        ]
        asset_repo = _make_mock_repo(assets)
        lib_repo = _make_mock_lib_repo()

        result = auto_select_video_assets(
            project_id="proj-1",
            asset_library_repo=lib_repo,
            asset_repo=asset_repo,
        )

        assert len(result) == 1
        assert result[0] == "a1"

    def test_only_video_mime_selected(self):
        """只有 video/* mime_type 的素材才会被选中."""
        from app.api.routes._helpers import auto_select_video_assets

        assets = [
            _make_asset("a1", mime_type="video/mp4", codec="h264"),
            _make_asset("a2", mime_type="image/jpeg"),
            _make_asset("a3", mime_type="audio/mpeg"),
        ]
        asset_repo = _make_mock_repo(assets)
        lib_repo = _make_mock_lib_repo()

        result = auto_select_video_assets(
            project_id="proj-1",
            asset_library_repo=lib_repo,
            asset_repo=asset_repo,
        )

        assert len(result) == 1
        assert result[0] == "a1"

    def test_empty_project_returns_empty(self):
        """空 project_id → 返回空列表."""
        from app.api.routes._helpers import auto_select_video_assets

        asset_repo = _make_mock_repo([])
        lib_repo = _make_mock_lib_repo()

        result = auto_select_video_assets(
            project_id="",
            asset_library_repo=lib_repo,
            asset_repo=asset_repo,
        )

        assert result == []

    def test_no_video_library_returns_empty(self):
        """没有视频素材库 → 返回空列表."""
        from app.api.routes._helpers import auto_select_video_assets

        image_lib = AssetLibrary(
            id="lib-image",
            project_id="proj-1",
            name="图片",
            kind=AssetLibraryKind.IMAGE,
        )
        lib_repo = MagicMock()
        lib_repo.find_by_project.return_value = [image_lib]

        asset_repo = _make_mock_repo([])

        result = auto_select_video_assets(
            project_id="proj-1",
            asset_library_repo=lib_repo,
            asset_repo=asset_repo,
        )

        assert result == []

    def test_sorted_by_created_at_desc(self):
        """结果按创建时间倒序（新素材在前）."""
        from datetime import datetime, timedelta, timezone

        from app.api.routes._helpers import auto_select_video_assets

        now = datetime.now(timezone.utc)
        assets = [
            _make_asset("oldest", codec="h264", created_at=now - timedelta(hours=2)),
            _make_asset("newest", codec="h264", created_at=now),
            _make_asset("middle", codec="h264", created_at=now - timedelta(hours=1)),
        ]
        asset_repo = _make_mock_repo(assets)
        lib_repo = _make_mock_lib_repo()

        result = auto_select_video_assets(
            project_id="proj-1",
            asset_library_repo=lib_repo,
            asset_repo=asset_repo,
        )

        assert result == ["newest", "middle", "oldest"]

    def test_landscape_videos_filtered_out(self):
        """横屏视频（width > height）被过滤掉."""
        from app.api.routes._helpers import auto_select_video_assets

        assets = [
            _make_asset("portrait1", codec="h264", width=1080, height=1920),
            _make_asset("landscape1", codec="h264", width=1920, height=1080),
            _make_asset("portrait2", codec="h264", width=720, height=1280),
            _make_asset("landscape2", codec="h264", width=1280, height=720),
        ]
        asset_repo = _make_mock_repo(assets)
        lib_repo = _make_mock_lib_repo()

        result = auto_select_video_assets(
            project_id="proj-1",
            asset_library_repo=lib_repo,
            asset_repo=asset_repo,
        )

        assert set(result) == {"portrait1", "portrait2"}
        assert len(result) == 2

    def test_square_videos_allowed(self):
        """正方形视频（width == height）不被过滤."""
        from app.api.routes._helpers import auto_select_video_assets

        assets = [
            _make_asset("square", codec="h264", width=720, height=720),
            _make_asset("portrait", codec="h264", width=1080, height=1920),
        ]
        asset_repo = _make_mock_repo(assets)
        lib_repo = _make_mock_lib_repo()

        result = auto_select_video_assets(
            project_id="proj-1",
            asset_library_repo=lib_repo,
            asset_repo=asset_repo,
        )

        assert "square" in result
        assert "portrait" in result

    def test_unknown_size_not_filtered(self):
        """尺寸未知的素材不被过滤（避免误杀存量数据）."""
        from app.api.routes._helpers import auto_select_video_assets

        assets = [
            _make_asset("unknown", codec="h264", width=0, height=0),
            _make_asset("portrait", codec="h264", width=1080, height=1920),
        ]
        asset_repo = _make_mock_repo(assets)
        lib_repo = _make_mock_lib_repo()

        result = auto_select_video_assets(
            project_id="proj-1",
            asset_library_repo=lib_repo,
            asset_repo=asset_repo,
        )

        assert "unknown" in result
        assert "portrait" in result

    def test_metadata_size_fallback(self):
        """width/height字段为空时从metadata兜底读取."""
        from app.api.routes._helpers import auto_select_video_assets

        assets = [
            _make_asset(
                "landscape_in_meta",
                codec="h264",
                width=0,
                height=0,
                metadata={"width": 1920, "height": 1080},
            ),
            _make_asset(
                "portrait_in_meta",
                codec="h264",
                width=0,
                height=0,
                metadata={"width": 1080, "height": 1920},
            ),
        ]
        asset_repo = _make_mock_repo(assets)
        lib_repo = _make_mock_lib_repo()

        result = auto_select_video_assets(
            project_id="proj-1",
            asset_library_repo=lib_repo,
            asset_repo=asset_repo,
        )

        assert "landscape_in_meta" not in result
        assert "portrait_in_meta" in result

    def test_only_landscape_filtered_codec_not_filtered(self):
        """只有横屏过滤生效，编码不再过滤."""
        from app.api.routes._helpers import auto_select_video_assets

        assets = [
            _make_asset("good", codec="h264", width=1080, height=1920),
            _make_asset("hevc_portrait", codec="hevc", width=1080, height=1920),
            _make_asset("bad_landscape", codec="h264", width=1920, height=1080),
            _make_asset("hevc_landscape", codec="hevc", width=1920, height=1080),
        ]
        asset_repo = _make_mock_repo(assets)
        lib_repo = _make_mock_lib_repo()

        result = auto_select_video_assets(
            project_id="proj-1",
            asset_library_repo=lib_repo,
            asset_repo=asset_repo,
        )

        # 只有横屏被过滤，编码不再过滤
        assert len(result) == 2
        assert "good" in result
        assert "hevc_portrait" in result
        assert "bad_landscape" not in result
        assert "hevc_landscape" not in result
