"""
密码哈希工具测试
"""

import pytest

from packages.application.auth.password_hasher import PasswordHasher, PasswordValidator


class TestPasswordHasher:
    """密码哈希测试"""

    @pytest.fixture
    def hasher(self):
        """创建密码哈希器"""
        return PasswordHasher(rounds=4)  # 测试用低 cost，加快速度

    def test_hash_password(self, hasher):
        """测试密码哈希"""
        password = "MySecurePassword123"
        hashed = hasher.hash_password(password)

        assert isinstance(hashed, str)
        assert len(hashed) > 0
        assert hashed != password  # 哈希后不等于原文
        assert hashed.startswith("$2b$")  # bcrypt 格式

    def test_hash_same_password_different_result(self, hasher):
        """测试相同密码每次哈希结果不同（因为 salt 不同）"""
        password = "MySecurePassword123"
        hash1 = hasher.hash_password(password)
        hash2 = hasher.hash_password(password)

        assert hash1 != hash2  # salt 不同，哈希不同

    def test_verify_correct_password(self, hasher):
        """测试验证正确的密码"""
        password = "MySecurePassword123"
        hashed = hasher.hash_password(password)

        assert hasher.verify_password(password, hashed) is True

    def test_verify_incorrect_password(self, hasher):
        """测试验证错误的密码"""
        password = "MySecurePassword123"
        hashed = hasher.hash_password(password)

        assert hasher.verify_password("WrongPassword", hashed) is False

    def test_verify_empty_password(self, hasher):
        """测试空密码验证"""
        hashed = hasher.hash_password("test")

        assert hasher.verify_password("", hashed) is False

    def test_verify_empty_hash(self, hasher):
        """测试空哈希验证"""
        assert hasher.verify_password("test", "") is False

    def test_verify_invalid_hash(self, hasher):
        """测试无效的哈希"""
        assert hasher.verify_password("test", "invalid-hash") is False

    def test_hash_empty_password(self, hasher):
        """测试哈希空密码应该失败"""
        with pytest.raises(ValueError, match="Password cannot be empty"):
            hasher.hash_password("")

    def test_invalid_rounds(self):
        """测试无效的 rounds 参数"""
        with pytest.raises(ValueError, match="rounds must be between 4 and 31"):
            PasswordHasher(rounds=2)

        with pytest.raises(ValueError, match="rounds must be between 4 and 31"):
            PasswordHasher(rounds=50)

    def test_unicode_password(self, hasher):
        """测试 Unicode 密码"""
        password = "密码123!@#"
        hashed = hasher.hash_password(password)

        assert hasher.verify_password(password, hashed) is True
        assert hasher.verify_password("错误密码", hashed) is False


class TestPasswordValidator:
    """密码验证器测试"""

    @pytest.fixture
    def validator(self):
        """创建密码验证器"""
        return PasswordValidator(
            min_length=8,
            require_uppercase=True,
            require_lowercase=True,
            require_digit=True,
            require_special=False,
        )

    def test_valid_password(self, validator):
        """测试有效密码"""
        valid, error = validator.validate("MyPassword123")
        assert valid is True
        assert error is None

    def test_password_too_short(self, validator):
        """测试密码太短"""
        valid, error = validator.validate("Pass1")
        assert valid is False
        assert "at least 8 characters" in error

    def test_password_no_uppercase(self, validator):
        """测试没有大写字母"""
        valid, error = validator.validate("mypassword123")
        assert valid is False
        assert "uppercase letter" in error

    def test_password_no_lowercase(self, validator):
        """测试没有小写字母"""
        valid, error = validator.validate("MYPASSWORD123")
        assert valid is False
        assert "lowercase letter" in error

    def test_password_no_digit(self, validator):
        """测试没有数字"""
        valid, error = validator.validate("MyPassword")
        assert valid is False
        assert "digit" in error

    def test_password_with_special_chars(self):
        """测试要求特殊字符"""
        validator = PasswordValidator(
            min_length=8,
            require_uppercase=True,
            require_lowercase=True,
            require_digit=True,
            require_special=True,
        )

        # 没有特殊字符
        valid, error = validator.validate("MyPassword123")
        assert valid is False
        assert "special character" in error

        # 有特殊字符
        valid, error = validator.validate("MyPassword123!")
        assert valid is True
        assert error is None

    def test_empty_password(self, validator):
        """测试空密码"""
        valid, error = validator.validate("")
        assert valid is False
        assert "cannot be empty" in error

    def test_custom_min_length(self):
        """测试自定义最小长度"""
        validator = PasswordValidator(
            min_length=12,
            require_uppercase=False,
            require_lowercase=False,
            require_digit=False,
            require_special=False,
        )

        valid, error = validator.validate("short")
        assert valid is False
        assert "at least 12 characters" in error

        valid, error = validator.validate("longenoughpassword")
        assert valid is True
        assert error is None
