"""Password Handler 单元测试."""

from __future__ import annotations

import pytest

from packages.application.auth.password_handler import (
    PasswordHandler,
    configure_password_handler,
    get_password_handler,
)


@pytest.fixture
def password_handler():
    return PasswordHandler(rounds=4)  # 用低rounds加速测试


class TestPasswordHandler:
    """PasswordHandler 测试"""

    def test_hash_password_returns_string(self, password_handler):
        """哈希密码返回非空字符串"""
        hashed = password_handler.hash_password("MyP@ssw0rd!")

        assert isinstance(hashed, str)
        assert len(hashed) > 0
        assert hashed != "MyP@ssw0rd!"

    def test_hash_password_different_each_time(self, password_handler):
        """同一密码每次哈希结果不同（加盐）"""
        h1 = password_handler.hash_password("TestPass123")
        h2 = password_handler.hash_password("TestPass123")

        assert h1 != h2

    def test_verify_password_correct(self, password_handler):
        """正确密码验证通过"""
        hashed = password_handler.hash_password("CorrectPass1!")
        assert password_handler.verify_password("CorrectPass1!", hashed) is True

    def test_verify_password_wrong(self, password_handler):
        """错误密码验证失败"""
        hashed = password_handler.hash_password("RightPass1!")
        assert password_handler.verify_password("WrongPass1!", hashed) is False

    def test_verify_password_empty_string(self, password_handler):
        """空字符串密码也能正确验证（不匹配）"""
        hashed = password_handler.hash_password("SomePass1!")
        assert password_handler.verify_password("", hashed) is False

    def test_hash_empty_password_raises(self, password_handler):
        """空密码哈希抛出 ValueError"""
        with pytest.raises(ValueError):
            password_handler.hash_password("")

    def test_needs_rehash_with_different_rounds(self):
        """不同 rounds 的哈希需要重新计算"""
        handler_low = PasswordHandler(rounds=4)
        handler_high = PasswordHandler(rounds=5)

        hashed = handler_low.hash_password("TestPass1!")
        assert handler_low.needs_rehash(hashed) is False
        assert handler_high.needs_rehash(hashed) is True

    def test_validate_strength_strong_password(self, password_handler):
        """强密码通过强度验证"""
        valid, error = password_handler.validate_strength("Str0ngP@ss!")

        assert valid is True
        assert error is None

    def test_validate_strength_too_short(self, password_handler):
        """密码太短不通过"""
        valid, error = password_handler.validate_strength("Sh0rt!")

        assert valid is False
        assert error is not None
        assert "长度" in error or "length" in error.lower() or "8" in error

    def test_validate_strength_no_uppercase(self, password_handler):
        """没有大写字母不通过"""
        valid, error = password_handler.validate_strength("lowercase1!")

        assert valid is False
        assert error is not None

    def test_validate_strength_no_lowercase(self, password_handler):
        """没有小写字母不通过"""
        valid, error = password_handler.validate_strength("UPPERCASE1!")

        assert valid is False
        assert error is not None

    def test_validate_strength_no_digit(self, password_handler):
        """没有数字不通过"""
        valid, error = password_handler.validate_strength("NoDigitPass!")

        assert valid is False
        assert error is not None

    def test_validate_strength_special_not_required(self, password_handler):
        """默认不要求特殊字符"""
        valid, error = password_handler.validate_strength("NoSpecial1")

        # 没有特殊字符也应该通过（require_special=False）
        assert valid is True
        assert error is None

    def test_validate_strength_empty_string(self, password_handler):
        """空字符串验证失败"""
        valid, error = password_handler.validate_strength("")

        assert valid is False
        assert error is not None

    def test_hash_and_verify_roundtrip(self, password_handler):
        """哈希-验证完整往返"""
        passwords = [
            "Simple12",
            "C0mpl3x!Pass",
            "12345678aA",
            "user@example.com1",
        ]
        for pwd in passwords:
            hashed = password_handler.hash_password(pwd)
            assert password_handler.verify_password(pwd, hashed)
            assert not password_handler.verify_password(pwd + "x", hashed)


class TestGlobalPasswordHandler:
    """全局密码处理器配置测试"""

    def test_get_password_handler_default(self):
        """未配置时 get_password_handler 返回默认实例"""
        import packages.application.auth.password_handler as pw_module

        pw_module._default_handler = None

        handler = get_password_handler()
        assert isinstance(handler, PasswordHandler)

    def test_configure_creates_handler(self):
        """configure_password_handler 创建并返回 handler"""
        import packages.application.auth.password_handler as pw_module

        pw_module._default_handler = None

        handler = configure_password_handler(rounds=4)

        assert isinstance(handler, PasswordHandler)
        assert get_password_handler() is handler

    def test_configure_overwrites_existing(self):
        """重新配置会覆盖之前的 handler"""
        import packages.application.auth.password_handler as pw_module

        pw_module._default_handler = None

        handler1 = configure_password_handler(rounds=4)
        handler2 = configure_password_handler(rounds=5)

        assert handler1 is not handler2
        assert get_password_handler() is handler2

    def test_get_password_handler_lazy_init(self):
        """未配置时首次调用 get_password_handler 会懒初始化"""
        import packages.application.auth.password_handler as pw_module

        pw_module._default_handler = None

        assert pw_module._default_handler is None
        handler = get_password_handler()
        assert pw_module._default_handler is not None
        assert pw_module._default_handler is handler
