"""JWT Handler 单元测试."""

from __future__ import annotations

import time

import pytest
from jwt.exceptions import ExpiredSignatureError, InvalidTokenError

from packages.application.auth.jwt_handler import (
    JWTHandler,
    configure_jwt_handler,
    get_jwt_handler,
)


@pytest.fixture
def jwt_handler():
    return JWTHandler(
        secret_key="test-secret-key-12345",
        algorithm="HS256",
        access_token_expire_minutes=30,
    )


class TestJWTHandler:
    """JWTHandler 测试"""

    def test_create_access_token_returns_string(self, jwt_handler):
        """创建 access_token 返回非空字符串"""
        token = jwt_handler.create_access_token(user_id="user_001")

        assert isinstance(token, str)
        assert len(token) > 0

    def test_create_access_token_with_role(self, jwt_handler):
        """创建带 role 的 access_token"""
        token = jwt_handler.create_access_token(user_id="user_001", role="admin")
        payload = jwt_handler.verify_access_token(token)

        assert payload["sub"] == "user_001"
        assert payload["role"] == "admin"

    def test_create_access_token_with_additional_claims(self, jwt_handler):
        """创建带额外声明的 access_token"""
        token = jwt_handler.create_access_token(
            user_id="user_001",
            additional_claims={"email": "test@example.com", "tenant": "t1"},
        )
        payload = jwt_handler.verify_access_token(token)

        assert payload["sub"] == "user_001"
        assert payload["email"] == "test@example.com"
        assert payload["tenant"] == "t1"

    def test_verify_access_token_success(self, jwt_handler):
        """验证有效 access_token"""
        token = jwt_handler.create_access_token(user_id="user_001")
        payload = jwt_handler.verify_access_token(token)

        assert payload["sub"] == "user_001"
        assert "exp" in payload
        assert "iat" in payload

    def test_verify_access_token_type_check(self, jwt_handler):
        """verify_access_token 验证 token 类型为 access"""
        token = jwt_handler.create_access_token(user_id="user_001")
        payload = jwt_handler.verify_access_token(token)

        assert payload.get("type") == "access" or "type" in payload

    def test_verify_token_no_type_restriction(self, jwt_handler):
        """verify_token 不限制 token 类型"""
        token = jwt_handler.create_access_token(user_id="user_001")
        payload = jwt_handler.verify_token(token)

        assert payload["sub"] == "user_001"

    def test_expired_token_raises_error(self):
        """过期 token 验证失败"""
        handler = JWTHandler(
            secret_key="test-secret",
            access_token_expire_minutes=-1,  # 立即过期
        )
        token = handler.create_access_token(user_id="user_001")

        # 等待一小段时间确保过期
        time.sleep(0.1)

        with pytest.raises(ExpiredSignatureError):
            handler.verify_access_token(token)

    def test_invalid_token_raises_error(self, jwt_handler):
        """无效 token 验证失败"""
        with pytest.raises(InvalidTokenError):
            jwt_handler.verify_access_token("invalid.token.here")

    def test_empty_token_raises_error(self, jwt_handler):
        """空字符串 token 验证失败"""
        with pytest.raises(InvalidTokenError):
            jwt_handler.verify_access_token("")

    def test_different_secret_fails_verification(self):
        """不同密钥生成的 token 无法互相验证"""
        handler1 = JWTHandler(secret_key="secret-one")
        handler2 = JWTHandler(secret_key="secret-two")

        token = handler1.create_access_token(user_id="user_001")

        with pytest.raises(InvalidTokenError):
            handler2.verify_access_token(token)

    def test_custom_algorithm(self):
        """支持自定义算法"""
        handler = JWTHandler(
            secret_key="test-secret",
            algorithm="HS256",
        )
        token = handler.create_access_token(user_id="user_001")
        payload = handler.verify_access_token(token)

        assert payload["sub"] == "user_001"

    def test_default_role_is_empty_string(self, jwt_handler):
        """不传 role 时默认为空字符串"""
        token = jwt_handler.create_access_token(user_id="user_001")
        payload = jwt_handler.verify_access_token(token)

        assert payload.get("role", "") == ""


class TestGlobalJWTHandler:
    """全局 JWT handler 配置测试"""

    def test_configure_creates_handler(self):
        """configure_jwt_handler 创建并返回 handler"""
        import packages.application.auth.jwt_handler as jwt_module

        # 重置全局状态
        jwt_module._default_handler = None

        handler = configure_jwt_handler(
            secret_key="global-secret",
            access_token_expire_minutes=60,
        )

        assert isinstance(handler, JWTHandler)
        assert get_jwt_handler() is handler

    def test_get_jwt_handler_without_config_raises(self):
        """未配置时调用 get_jwt_handler 抛出 RuntimeError"""
        import packages.application.auth.jwt_handler as jwt_module

        # 重置全局状态
        jwt_module._default_handler = None

        with pytest.raises(RuntimeError, match="JWT handler not configured"):
            get_jwt_handler()

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

        jwt_module._default_handler = None

        handler1 = configure_jwt_handler(secret_key="first-secret")
        handler2 = configure_jwt_handler(secret_key="second-secret")

        assert handler1 is not handler2
        assert get_jwt_handler() is handler2
