"""InMemoryAssetLibraryRepository 单测 — 素材库仓储内存实现."""

from __future__ import annotations

import pytest

from packages.adapters.in_memory.asset_library_repository import (
    InMemoryAssetLibraryRepository,
)
from packages.domain import AssetLibrary, AssetLibraryKind

# ── Fixtures ───────────────────────────────────────────────────────────────


@pytest.fixture
def repo():
    return InMemoryAssetLibraryRepository()


@pytest.fixture
def sample_libraries(repo):
    """创建几个测试素材库."""
    libs = []
    for i, kind in enumerate(
        [
            AssetLibraryKind.VIDEO,
            AssetLibraryKind.VOICE,
            AssetLibraryKind.IMAGE,
        ]
    ):
        lib = AssetLibrary.create(
            project_id="proj-1",
            name=f"Library {i}",
            kind=kind,
        )
        libs.append(repo.create(lib))
    # 另一个项目的
    lib2 = AssetLibrary.create(
        project_id="proj-2",
        name="Other Project Lib",
        kind=AssetLibraryKind.VIDEO,
    )
    libs.append(repo.create(lib2))
    return libs


# ── CRUD 基本操作 ──────────────────────────────────────────────────────────


class TestAssetLibraryRepoCRUD:
    """基本 CRUD 操作."""

    def test_create_and_get(self, repo):
        lib = AssetLibrary.create(project_id="p1", name="Test Lib", kind=AssetLibraryKind.VIDEO)
        created = repo.create(lib)
        assert created.id == lib.id
        assert created.name == "Test Lib"

        fetched = repo.get(lib.id)
        assert fetched is not None
        assert fetched.kind == AssetLibraryKind.VIDEO

    def test_get_not_found(self, repo):
        assert repo.get("nonexistent") is None

    def test_find_by_id_alias(self, repo):
        lib = AssetLibrary.create(project_id="p1", name="Test", kind=AssetLibraryKind.VOICE)
        repo.create(lib)
        assert repo.find_by_id(lib.id).id == lib.id

    def test_update(self, repo):
        lib = AssetLibrary.create(project_id="p1", name="Old Name", kind=AssetLibraryKind.IMAGE)
        repo.create(lib)

        lib.name = "New Name"
        updated = repo.update(lib)
        assert updated.name == "New Name"

        fetched = repo.get(lib.id)
        assert fetched.name == "New Name"

    def test_delete_existing(self, repo):
        lib = AssetLibrary.create(project_id="p1", name="To Delete", kind=AssetLibraryKind.VIDEO)
        repo.create(lib)

        result = repo.delete(lib.id)
        assert result is True
        assert repo.get(lib.id) is None

    def test_delete_nonexistent(self, repo):
        result = repo.delete("nonexistent")
        assert result is False


# ── 查询方法 ───────────────────────────────────────────────────────────────


class TestAssetLibraryRepoQueries:
    """查询类方法."""

    def test_find_by_project_all_kinds(self, repo, sample_libraries):
        result = repo.find_by_project("proj-1")
        assert len(result) == 3

    def test_find_by_project_filter_by_kind(self, repo, sample_libraries):
        result = repo.find_by_project("proj-1", kind=AssetLibraryKind.VIDEO)
        assert len(result) == 1
        assert result[0].kind == AssetLibraryKind.VIDEO

    def test_find_by_project_empty(self, repo):
        result = repo.find_by_project("nonexistent")
        assert result == []

    def test_find_by_project_with_kind_none_returns_all(self, repo, sample_libraries):
        result = repo.find_by_project("proj-1", kind=None)
        assert len(result) == 3


# ── 计数方法 ───────────────────────────────────────────────────────────────


class TestAssetLibraryRepoCounting:
    """素材计数相关方法."""

    def test_increment_asset_count(self, repo):
        lib = AssetLibrary.create(project_id="p1", name="Test", kind=AssetLibraryKind.VIDEO)
        repo.create(lib)
        assert lib.asset_count == 0
        assert lib.total_size == 0

        repo.increment_asset_count(lib.id, 1024)
        fetched = repo.get(lib.id)
        assert fetched.asset_count == 1
        assert fetched.total_size == 1024

        repo.increment_asset_count(lib.id, 2048)
        fetched = repo.get(lib.id)
        assert fetched.asset_count == 2
        assert fetched.total_size == 3072

    def test_decrement_asset_count(self, repo):
        lib = AssetLibrary.create(project_id="p1", name="Test", kind=AssetLibraryKind.VIDEO)
        lib.asset_count = 3
        lib.total_size = 3000
        repo.create(lib)

        repo.decrement_asset_count(lib.id, 1000)
        fetched = repo.get(lib.id)
        assert fetched.asset_count == 2
        assert fetched.total_size == 2000

    def test_decrement_not_below_zero(self, repo):
        """计数和大小不会减到负数."""
        lib = AssetLibrary.create(project_id="p1", name="Test", kind=AssetLibraryKind.VIDEO)
        lib.asset_count = 1
        lib.total_size = 100
        repo.create(lib)

        # 减 2 次，应该被钳制到 0
        repo.decrement_asset_count(lib.id, 200)
        fetched = repo.get(lib.id)
        assert fetched.asset_count == 0
        assert fetched.total_size == 0

    def test_increment_nonexistent_library_no_error(self, repo):
        """对不存在的素材库操作，不抛异常也无效果."""
        repo.increment_asset_count("nonexistent", 100)
        # 不报错
        assert repo.get("nonexistent") is None

    def test_decrement_nonexistent_library_no_error(self, repo):
        repo.decrement_asset_count("nonexistent", 100)
        assert repo.get("nonexistent") is None
