"""素材打标/取消标签单元测试。"""

import pytest

from packages.adapters.in_memory.asset_repository import InMemoryAssetRepository
from packages.adapters.in_memory.tag_repository import InMemoryTagRepository
from packages.domain import Asset, Tag


@pytest.fixture
def asset_repo():
    return InMemoryAssetRepository()


@pytest.fixture
def tag_repo():
    return InMemoryTagRepository()


def _create_asset(asset_repo, **kwargs):
    defaults = dict(
        project_id="proj-1",
        library_id="lib-1",
        name="video.mp4",
        storage_key="uploads/abc/video.mp4",
        mime_type="video/mp4",
    )
    defaults.update(kwargs)
    asset = Asset.create(**defaults)
    return asset_repo.create(asset)


def test_tag_asset(asset_repo, tag_repo):
    """测试给素材打标签。"""
    asset = _create_asset(asset_repo)
    tag = tag_repo.create(Tag.create(user_id="user-1", name="风景"))

    asset.add_tag(tag.id)
    asset_repo.update(asset)

    loaded = asset_repo.get(asset.id)
    assert tag.id in loaded.tag_ids


def test_untag_asset(asset_repo, tag_repo):
    """测试取消素材标签。"""
    asset = _create_asset(asset_repo)
    tag = tag_repo.create(Tag.create(user_id="user-1", name="风景"))

    asset.add_tag(tag.id)
    asset_repo.update(asset)

    asset.remove_tag(tag.id)
    asset_repo.update(asset)

    loaded = asset_repo.get(asset.id)
    assert tag.id not in loaded.tag_ids


def test_tag_multiple_assets(asset_repo, tag_repo):
    """测试同一标签打给多个素材。"""
    a1 = _create_asset(asset_repo, name="a.mp4")
    a2 = _create_asset(asset_repo, name="b.mp4")
    tag = tag_repo.create(Tag.create(user_id="user-1", name="风景"))

    a1.add_tag(tag.id)
    a2.add_tag(tag.id)
    asset_repo.update(a1)
    asset_repo.update(a2)

    assert tag.id in asset_repo.get(a1.id).tag_ids
    assert tag.id in asset_repo.get(a2.id).tag_ids


def test_find_by_tag_ids(asset_repo, tag_repo):
    """测试按标签 ID 筛选素材。"""
    tag1 = tag_repo.create(Tag.create(user_id="user-1", name="风景"))
    tag2 = tag_repo.create(Tag.create(user_id="user-1", name="自然"))

    a1 = _create_asset(asset_repo, name="a.mp4")
    a1.add_tag(tag1.id)
    a1.add_tag(tag2.id)
    asset_repo.update(a1)

    a2 = _create_asset(asset_repo, name="b.mp4")
    a2.add_tag(tag1.id)
    asset_repo.update(a2)

    _create_asset(asset_repo, name="c.mp4")
    # 无标签

    # 按 tag1 筛选 → a1, a2
    result = asset_repo.find_by_tag_ids([tag1.id])
    ids = {a.id for a in result}
    assert ids == {a1.id, a2.id}

    # 按 tag1 + tag2 筛选（交集）→ a1
    result = asset_repo.find_by_tag_ids([tag1.id, tag2.id])
    ids = {a.id for a in result}
    assert ids == {a1.id}

    # 空 tag_ids → 空结果
    assert asset_repo.find_by_tag_ids([]) == []


def test_delete_tag_cleans_associations(asset_repo, tag_repo):
    """测试删除标签后素材的 tag_ids 不受影响（关联表由仓储层清理）。"""
    asset = _create_asset(asset_repo)
    tag = tag_repo.create(Tag.create(user_id="user-1", name="风景"))

    asset.add_tag(tag.id)
    asset_repo.update(asset)

    # 删除标签
    tag_repo.delete(tag.id)
    assert tag_repo.get(tag.id) is None

    # 素材的 tag_ids 在内存中仍有，但重新加载后 InMemory 不感知关联表
    # 实际 SQLAlchemy 实现中 _sync_asset_tags 会在 update 时清理


def test_duplicate_tag_id_ignored(asset_repo, tag_repo):
    """测试重复打同一标签自动去重。"""
    asset = _create_asset(asset_repo)
    tag = tag_repo.create(Tag.create(user_id="user-1", name="风景"))

    asset.add_tag(tag.id)
    asset.add_tag(tag.id)  # 重复

    assert asset.tag_ids.count(tag.id) == 1
