"""
In-Memory 标签仓储测试.
"""

from __future__ import annotations

import time
from datetime import datetime

import pytest

from packages.adapters.in_memory.tag_repository import InMemoryTagRepository
from packages.domain import Tag


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


@pytest.fixture
def make_tag():
    counter = 0

    def _make(user_id: str = "user_1", name: str = "默认标签"):
        nonlocal counter
        counter += 1
        return Tag(
            id=f"tag_{counter}",
            user_id=user_id,
            name=name,
            created_at=datetime.now(),
        )

    return _make


class TestInMemoryTagRepositoryCreate:
    """创建标签."""

    def test_create_tag(self, repo, make_tag):
        tag = make_tag()
        result = repo.create(tag)
        assert result.id == tag.id
        assert result.name == tag.name

    def test_create_same_id_overwrites(self, repo, make_tag):
        tag = make_tag(name="first")
        repo.create(tag)
        tag.name = "second"
        repo.create(tag)
        found = repo.get(tag.id)
        assert found.name == "second"


class TestInMemoryTagRepositoryGet:
    """获取标签."""

    def test_get_existing(self, repo, make_tag):
        tag = make_tag()
        repo.create(tag)
        found = repo.get(tag.id)
        assert found is not None
        assert found.id == tag.id

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


class TestInMemoryTagRepositoryFindByName:
    """按名称查找."""

    def test_find_by_name_found(self, repo, make_tag):
        tag = make_tag(name="风景")
        repo.create(tag)
        found = repo.find_by_name("user_1", "风景")
        assert found is not None
        assert found.id == tag.id

    def test_find_by_name_not_found(self, repo, make_tag):
        tag = make_tag(name="风景")
        repo.create(tag)
        assert repo.find_by_name("user_1", "美食") is None
        assert repo.find_by_name("user_2", "风景") is None

    def test_find_by_name_different_user(self, repo, make_tag):
        tag = make_tag(user_id="user_1", name="风景")
        repo.create(tag)
        assert repo.find_by_name("user_2", "风景") is None


class TestInMemoryTagRepositoryListByUser:
    """用户标签列表."""

    def test_list_by_user_empty(self, repo):
        result = repo.list_by_user("user_1")
        assert result == []

    def test_list_by_user_filters_correctly(self, repo, make_tag):
        for i in range(5):
            make_tag(user_id="user_1", name=f"标签{i}")
            repo.create(make_tag(user_id="user_1", name=f"标签{i}"))
        repo.create(make_tag(user_id="user_2", name="其他标签"))

        result = repo.list_by_user("user_1")
        assert len(result) == 5
        assert all(t.user_id == "user_1" for t in result)

    def test_list_sorted_by_created_desc(self, repo, make_tag):
        tags = []
        for i in range(3):
            tag = make_tag(name=f"t{i}")
            tag.created_at = datetime.fromtimestamp(1000 + i * 100)
            repo.create(tag)
            tags.append(tag)

        result = repo.list_by_user("user_1")
        assert len(result) == 3
        # 最新的排在前面
        assert result[0].created_at > result[2].created_at

    def test_list_pagination(self, repo, make_tag):
        for i in range(10):
            repo.create(make_tag(name=f"tag{i}"))

        page1 = repo.list_by_user("user_1", skip=0, limit=3)
        page2 = repo.list_by_user("user_1", skip=3, limit=3)
        assert len(page1) == 3
        assert len(page2) == 3
        assert page1[0].id != page2[0].id

    def test_list_limit_exceeds_total(self, repo, make_tag):
        for i in range(3):
            repo.create(make_tag(name=f"t{i}"))
        result = repo.list_by_user("user_1", skip=0, limit=100)
        assert len(result) == 3


class TestInMemoryTagRepositoryCount:
    """统计用户标签数."""

    def test_count_zero(self, repo):
        assert repo.count_by_user("user_1") == 0

    def test_count_correct(self, repo, make_tag):
        for i in range(7):
            repo.create(make_tag(user_id="user_1", name=f"t{i}"))
        repo.create(make_tag(user_id="user_2", name="other"))
        assert repo.count_by_user("user_1") == 7
        assert repo.count_by_user("user_2") == 1


class TestInMemoryTagRepositoryDelete:
    """删除标签."""

    def test_delete_existing(self, repo, make_tag):
        tag = make_tag()
        repo.create(tag)
        result = repo.delete(tag.id)
        assert result is True
        assert repo.get(tag.id) is None

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

    def test_delete_does_not_affect_others(self, repo, make_tag):
        t1 = make_tag(name="a")
        t2 = make_tag(name="b")
        repo.create(t1)
        repo.create(t2)
        repo.delete(t1.id)
        assert repo.get(t2.id) is not None
        assert repo.count_by_user("user_1") == 1
