"""
In-Memory 用户仓储测试.
"""

from __future__ import annotations

from datetime import datetime

import pytest

from packages.adapters.in_memory.user_repository import InMemoryUserRepository
from packages.domain.entities import User


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


@pytest.fixture
def sample_user():
    return User(
        id="user_1",
        email="test@example.com",
        display_name="Test User",
        username="testuser",
        password_hash="hashed",
        email_verified=True,
        email_verification_token="verify_token",
        password_reset_token="reset_token",
        wechat_openid="openid_123",
        wechat_unionid="unionid_123",
        phone="13800138000",
    )


class TestInMemoryUserRepositorySave:
    """保存用户."""

    def test_save_new_user(self, repo, sample_user):
        repo.save(sample_user)
        found = repo.find_by_id("user_1")
        assert found is not None
        assert found.email == "test@example.com"

    def test_save_updates_existing(self, repo, sample_user):
        repo.save(sample_user)
        sample_user.display_name = "Updated"
        repo.save(sample_user)
        found = repo.find_by_id("user_1")
        assert found.display_name == "Updated"

    def test_email_index_case_insensitive(self, repo, sample_user):
        repo.save(sample_user)
        found = repo.find_by_email("TEST@EXAMPLE.COM")
        assert found is not None
        assert found.id == "user_1"

    def test_username_index_case_insensitive(self, repo, sample_user):
        repo.save(sample_user)
        found = repo.find_by_username("TESTUSER")
        assert found is not None
        assert found.id == "user_1"


class TestInMemoryUserRepositoryFind:
    """各种查找方式."""

    def test_find_by_id_found(self, repo, sample_user):
        repo.save(sample_user)
        found = repo.find_by_id("user_1")
        assert found.id == "user_1"

    def test_find_by_id_not_found(self, repo):
        assert repo.find_by_id("nonexistent") is None

    def test_find_by_email_found(self, repo, sample_user):
        repo.save(sample_user)
        found = repo.find_by_email("test@example.com")
        assert found.id == "user_1"

    def test_find_by_email_not_found(self, repo):
        assert repo.find_by_email("no@example.com") is None

    def test_find_by_username_found(self, repo, sample_user):
        repo.save(sample_user)
        found = repo.find_by_username("testuser")
        assert found.id == "user_1"

    def test_find_by_username_not_found(self, repo):
        assert repo.find_by_username("nobody") is None

    def test_find_by_verification_token(self, repo, sample_user):
        repo.save(sample_user)
        found = repo.find_by_verification_token("verify_token")
        assert found.id == "user_1"

    def test_find_by_verification_token_not_found(self, repo):
        assert repo.find_by_verification_token("bad_token") is None

    def test_find_by_password_reset_token(self, repo, sample_user):
        repo.save(sample_user)
        found = repo.find_by_password_reset_token("reset_token")
        assert found.id == "user_1"

    def test_find_by_password_reset_token_not_found(self, repo):
        assert repo.find_by_password_reset_token("bad_token") is None

    def test_find_by_wechat_openid(self, repo, sample_user):
        repo.save(sample_user)
        found = repo.find_by_wechat_openid("openid_123")
        assert found.id == "user_1"

    def test_find_by_wechat_openid_not_found(self, repo):
        assert repo.find_by_wechat_openid("bad_openid") is None

    def test_find_by_wechat_unionid(self, repo, sample_user):
        repo.save(sample_user)
        found = repo.find_by_wechat_unionid("unionid_123")
        assert found.id == "user_1"

    def test_find_by_wechat_unionid_empty_returns_none(self, repo):
        """空 unionid 直接返回 None."""
        assert repo.find_by_wechat_unionid("") is None
        assert repo.find_by_wechat_unionid(None) is None  # type: ignore

    def test_find_by_wechat_unionid_not_found(self, repo):
        assert repo.find_by_wechat_unionid("bad_unionid") is None

    def test_find_by_phone(self, repo, sample_user):
        repo.save(sample_user)
        found = repo.find_by_phone("13800138000")
        assert found.id == "user_1"

    def test_find_by_phone_empty_returns_none(self, repo):
        assert repo.find_by_phone("") is None
        assert repo.find_by_phone(None) is None  # type: ignore

    def test_find_by_phone_not_found(self, repo):
        assert repo.find_by_phone("13900139000") is None

    def test_user_without_username_not_in_username_index(self, repo):
        user = User(id="u2", email="no_user@example.com", display_name="No Username")
        repo.save(user)
        assert repo.find_by_username("") is None


class TestInMemoryUserRepositoryDelete:
    """删除用户."""

    def test_delete_existing(self, repo, sample_user):
        repo.save(sample_user)
        result = repo.delete("user_1")
        assert result is True
        assert repo.find_by_id("user_1") is None
        assert repo.find_by_email("test@example.com") is None
        assert repo.find_by_username("testuser") is None
        assert repo.find_by_verification_token("verify_token") is None
        assert repo.find_by_password_reset_token("reset_token") is None

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

    def test_delete_cleans_wechat_and_phone_indexes(self, repo, sample_user):
        repo.save(sample_user)
        repo.delete("user_1")
        assert repo.find_by_wechat_openid("openid_123") is None
        assert repo.find_by_wechat_unionid("unionid_123") is None
        assert repo.find_by_phone("13800138000") is None


class TestInMemoryUserRepositoryMultipleUsers:
    """多用户场景."""

    def test_multiple_users(self, repo):
        for i in range(5):
            user = User(
                id=f"user_{i}",
                email=f"user{i}@example.com",
                display_name=f"User {i}",
                username=f"user{i}",
            )
            repo.save(user)

        for i in range(5):
            assert repo.find_by_id(f"user_{i}") is not None
            assert repo.find_by_email(f"user{i}@example.com") is not None
            assert repo.find_by_username(f"user{i}") is not None
