"""
用户注册 Use Case 测试
"""

from unittest.mock import Mock

import pytest

from packages.application.auth import (
    RegisterUserRequest,
    RegisterUserUseCase,
    VerifyEmailRequest,
    VerifyEmailUseCase,
)
from packages.domain.entities import User


class TestRegisterUserUseCase:
    """注册用例测试"""

    @pytest.fixture
    def mock_user_repo(self):
        """Mock 用户仓储"""
        repo = Mock()
        repo.find_by_email = Mock(return_value=None)
        repo.find_by_username = Mock(return_value=None)
        repo.find_by_verification_token = Mock(return_value=None)
        repo.save = Mock()
        return repo

    @pytest.fixture
    def use_case(self, mock_user_repo):
        """创建注册用例"""
        email_service = Mock()
        email_service.send_verification_email.return_value = (True, None)
        return RegisterUserUseCase(
            user_repository=mock_user_repo,
            base_url="https://test.com",
            email_service=email_service,
        )

    def test_register_user_success(self, use_case, mock_user_repo):
        """测试注册成功"""

        request = RegisterUserRequest(
            email="test@example.com",
            password="SecurePass123",
            username="testuser",
            display_name="Test User",
        )

        response, error = use_case.execute(request)

        assert error is None
        assert response is not None
        assert response.email == "test@example.com"
        assert response.username == "testuser"
        assert response.display_name == "Test User"
        assert response.email_verification_sent is True

        # 验证保存了用户
        mock_user_repo.save.assert_called_once()
        saved_user = mock_user_repo.save.call_args[0][0]
        assert saved_user.email == "test@example.com"
        assert saved_user.password_hash != ""
        assert saved_user.email_verified is False
        assert saved_user.email_verification_token is not None

    def test_register_user_weak_password(self, use_case):
        """测试弱密码"""
        request = RegisterUserRequest(
            email="test@example.com",
            password="weak",
            username="testuser",
            display_name="Test User",
        )

        response, error = use_case.execute(request)

        assert response is None
        assert error is not None
        assert "at least 8 characters" in error

    def test_register_user_email_exists(self, use_case, mock_user_repo):
        """测试邮箱已存在"""
        # Mock 返回已存在的用户
        existing_user = User(
            id="existing-id",
            email="test@example.com",
            username="existing",
            display_name="Existing",
        )
        mock_user_repo.find_by_email.return_value = existing_user

        request = RegisterUserRequest(
            email="test@example.com",
            password="SecurePass123",
            username="testuser",
            display_name="Test User",
        )

        response, error = use_case.execute(request)

        assert response is None
        assert error == "Email already registered"

    def test_register_user_username_taken(self, use_case, mock_user_repo):
        """测试用户名已被占用"""
        existing_user = User(
            id="existing-id",
            email="other@example.com",
            username="testuser",
            display_name="Other",
        )
        mock_user_repo.find_by_username.return_value = existing_user

        request = RegisterUserRequest(
            email="test@example.com",
            password="SecurePass123",
            username="testuser",
            display_name="Test User",
        )

        response, error = use_case.execute(request)

        assert response is None
        assert error == "Username already taken"

    def test_register_user_missing_email(self, use_case):
        """测试缺少邮箱"""
        request = RegisterUserRequest(
            email="",
            password="SecurePass123",
            username="testuser",
            display_name="Test User",
        )

        response, error = use_case.execute(request)

        assert response is None
        assert error == "Email is required"

    def test_register_user_email_send_failure(self, use_case, mock_user_repo):
        """测试邮件发送失败（用户仍然创建）"""
        use_case.email_service.send_verification_email.return_value = (
            False,
            "SMTP error",
        )

        request = RegisterUserRequest(
            email="test@example.com",
            password="SecurePass123",
            username="testuser",
            display_name="Test User",
        )

        response, error = use_case.execute(request)

        assert error is None  # 用户创建成功
        assert response is not None
        assert response.email_verification_sent is False  # 但邮件发送失败


class TestVerifyEmailUseCase:
    """邮箱验证用例测试"""

    @pytest.fixture
    def mock_user_repo(self):
        repo = Mock()
        repo.find_by_verification_token = Mock(return_value=None)
        repo.save = Mock()
        return repo

    @pytest.fixture
    def use_case(self, mock_user_repo):
        return VerifyEmailUseCase(user_repository=mock_user_repo)

    def test_verify_email_success(self, use_case, mock_user_repo):
        """测试验证成功"""
        user = User(
            id="user-123",
            email="test@example.com",
            username="testuser",
            display_name="Test User",
            email_verified=False,
            email_verification_token="valid-token",
        )
        mock_user_repo.find_by_verification_token.return_value = user

        request = VerifyEmailRequest(token="valid-token")
        success, error = use_case.execute(request)

        assert success is True
        assert error is None

        # 验证用户状态已更新
        assert user.email_verified is True
        assert user.email_verification_token is None
        mock_user_repo.save.assert_called_once()

    def test_verify_email_invalid_token(self, use_case, mock_user_repo):
        """测试无效令牌"""
        mock_user_repo.find_by_verification_token.return_value = None

        request = VerifyEmailRequest(token="invalid-token")
        success, error = use_case.execute(request)

        assert success is False
        assert error == "Invalid or expired verification token"

    def test_verify_email_already_verified(self, use_case, mock_user_repo):
        """测试已验证的邮箱"""
        user = User(
            id="user-123",
            email="test@example.com",
            username="testuser",
            display_name="Test User",
            email_verified=True,
            email_verification_token="old-token",
        )
        mock_user_repo.find_by_verification_token.return_value = user

        request = VerifyEmailRequest(token="old-token")
        success, error = use_case.execute(request)

        assert success is True  # 已验证也返回成功
        assert error is None
