"""Tests for API Key Authentication.

测试 API Key 认证功能。
"""

from __future__ import annotations

import pytest
from fastapi import HTTPException
from fastapi.security import HTTPAuthorizationCredentials

from sagellm_gateway.auth import APIKeyAuth
from sagellm_gateway.config import APIKeyConfig, SecurityConfig, set_security_config


@pytest.fixture
def auth_config():
    """配置测试环境的认证."""
    config = SecurityConfig(
        api_key=APIKeyConfig(
            enabled=True,
            api_keys={
                "sk-test-key-1": "user_alice",
                "sk-test-key-2": "user_bob",
                "sk-admin-key": "admin",
            },
        )
    )
    set_security_config(config)
    return config


@pytest.fixture
def disabled_auth_config():
    """配置测试环境（禁用认证）."""
    config = SecurityConfig(
        api_key=APIKeyConfig(enabled=False),
    )
    set_security_config(config)
    return config


@pytest.fixture
def mock_request():
    """创建模拟的 FastAPI Request."""

    class MockRequest:
        def __init__(self):
            self.url = type("URL", (), {"path": "/v1/chat/completions"})()
            self.method = "POST"
            self.state = type("State", (), {})()

    return MockRequest()


class TestAPIKeyAuth:
    """API Key 认证测试."""

    def test_verify_valid_api_key(self, auth_config):
        """测试验证有效的 API Key."""
        auth = APIKeyAuth()
        user_id = auth.verify_api_key("sk-test-key-1")
        assert user_id == "user_alice"

        user_id = auth.verify_api_key("sk-test-key-2")
        assert user_id == "user_bob"

    def test_verify_invalid_api_key(self, auth_config):
        """测试验证无效的 API Key."""
        auth = APIKeyAuth()
        user_id = auth.verify_api_key("invalid-key")
        assert user_id is None

    def test_verify_disabled_auth(self, disabled_auth_config):
        """测试禁用认证时返回匿名用户."""
        auth = APIKeyAuth()
        user_id = auth.verify_api_key("any-key")
        assert user_id == "anonymous"

    @pytest.mark.asyncio
    async def test_authenticate_success(self, auth_config, mock_request):
        """测试成功认证."""
        auth = APIKeyAuth()
        credentials = HTTPAuthorizationCredentials(scheme="Bearer", credentials="sk-test-key-1")

        user_id = await auth.authenticate(mock_request, credentials)
        assert user_id == "user_alice"
        assert mock_request.state.user_id == "user_alice"

    @pytest.mark.asyncio
    async def test_authenticate_missing_credentials(self, auth_config, mock_request):
        """测试缺失认证凭证."""
        auth = APIKeyAuth()

        with pytest.raises(HTTPException) as exc_info:
            await auth.authenticate(mock_request, None)

        assert exc_info.value.status_code == 401
        assert "missing_api_key" in str(exc_info.value.detail)

    @pytest.mark.asyncio
    async def test_authenticate_invalid_key(self, auth_config, mock_request):
        """测试无效的 API Key."""
        auth = APIKeyAuth()
        credentials = HTTPAuthorizationCredentials(scheme="Bearer", credentials="invalid-key")

        with pytest.raises(HTTPException) as exc_info:
            await auth.authenticate(mock_request, credentials)

        assert exc_info.value.status_code == 401
        assert "invalid_api_key" in str(exc_info.value.detail)

    @pytest.mark.asyncio
    async def test_authenticate_disabled(self, disabled_auth_config, mock_request):
        """测试禁用认证时不需要凭证."""
        auth = APIKeyAuth()
        user_id = await auth.authenticate(mock_request, None)
        assert user_id == "anonymous"


class TestMultipleAPIKeys:
    """测试多 API Key 支持."""

    def test_multiple_users(self, auth_config):
        """测试多个用户的 API Key."""
        auth = APIKeyAuth()

        # 验证多个用户
        assert auth.verify_api_key("sk-test-key-1") == "user_alice"
        assert auth.verify_api_key("sk-test-key-2") == "user_bob"
        assert auth.verify_api_key("sk-admin-key") == "admin"

    def test_unique_keys(self, auth_config):
        """测试 API Key 唯一性."""
        config = SecurityConfig(
            api_key=APIKeyConfig(
                enabled=True,
                api_keys={
                    "sk-key-1": "user1",
                    "sk-key-2": "user2",
                },
            )
        )
        set_security_config(config)

        auth = APIKeyAuth()
        assert auth.verify_api_key("sk-key-1") != auth.verify_api_key("sk-key-2")
