"""Unit tests for RequireAPIKey dependency."""

import pytest
from fastapi import Depends, FastAPI
from starlette.testclient import TestClient

from hezor_common.transfer.middlewares import (
    CredentialMiddleware,
    RequireAPIKey,
    require_api_key,
)


@pytest.fixture
def test_app():
    """Create a test FastAPI application."""
    app = FastAPI()
    return app


@pytest.fixture
def valid_api_key():
    """Return a valid API key for testing."""
    return "test-api-key-12345"


class TestRequireAPIKeyDefault:
    """Test default require_api_key instance."""

    def test_require_api_key_with_valid_key(self, test_app, valid_api_key):
        """Test require_api_key with valid API key."""
        test_app.add_middleware(CredentialMiddleware, api_key=valid_api_key)

        @test_app.get("/protected")
        async def protected_route(api_key: str = Depends(require_api_key)):
            return {"api_key": api_key}

        client = TestClient(test_app)
        response = client.get("/protected", headers={"Authorization": f"Bearer {valid_api_key}"})
        assert response.status_code == 200
        assert response.json()["api_key"] == valid_api_key

    def test_require_api_key_without_key(self, test_app, valid_api_key):
        """Test require_api_key without API key."""
        test_app.add_middleware(CredentialMiddleware, api_key=valid_api_key)

        @test_app.get("/protected")
        async def protected_route(api_key: str = Depends(require_api_key)):
            return {"api_key": api_key}

        client = TestClient(test_app)
        response = client.get("/protected")
        assert response.status_code == 401
        assert response.json()["detail"] == "API key required"
        assert "WWW-Authenticate" in response.headers
        assert "Bearer" in response.headers["WWW-Authenticate"]

    def test_require_api_key_with_invalid_key(self, test_app, valid_api_key):
        """Test require_api_key with invalid API key."""
        test_app.add_middleware(CredentialMiddleware, api_key=valid_api_key)

        @test_app.get("/protected")
        async def protected_route(api_key: str = Depends(require_api_key)):
            return {"api_key": api_key}

        client = TestClient(test_app)
        response = client.get("/protected", headers={"Authorization": "Bearer wrong-key"})
        assert response.status_code == 401
        assert response.json()["detail"] == "Invalid API key"
        assert "WWW-Authenticate" in response.headers

    def test_require_api_key_with_malformed_header(self, test_app, valid_api_key):
        """Test require_api_key with malformed Authorization header."""
        test_app.add_middleware(CredentialMiddleware, api_key=valid_api_key)

        @test_app.get("/protected")
        async def protected_route(api_key: str = Depends(require_api_key)):
            return {"api_key": api_key}

        client = TestClient(test_app)
        response = client.get("/protected", headers={"Authorization": valid_api_key})
        assert response.status_code == 401
        assert response.json()["detail"] == "Invalid Authorization header format"


class TestRequireAPIKeyCustomRealm:
    """Test RequireAPIKey with custom realm."""

    def test_custom_realm_in_header(self, test_app, valid_api_key):
        """Test custom realm appears in WWW-Authenticate header."""
        test_app.add_middleware(CredentialMiddleware, api_key=valid_api_key)

        @test_app.get("/admin")
        async def admin_route(api_key: str = Depends(RequireAPIKey("Admin area"))):
            return {"api_key": api_key}

        client = TestClient(test_app)
        response = client.get("/admin")
        assert response.status_code == 401
        assert "WWW-Authenticate" in response.headers
        assert 'realm="Admin area"' in response.headers["WWW-Authenticate"]

    def test_custom_realm_with_valid_key(self, test_app, valid_api_key):
        """Test custom realm with valid API key."""
        test_app.add_middleware(CredentialMiddleware, api_key=valid_api_key)

        @test_app.get("/admin")
        async def admin_route(api_key: str = Depends(RequireAPIKey("Admin area"))):
            return {"api_key": api_key}

        client = TestClient(test_app)
        response = client.get("/admin", headers={"Authorization": f"Bearer {valid_api_key}"})
        assert response.status_code == 200
        assert response.json()["api_key"] == valid_api_key

    def test_default_realm_value(self, test_app, valid_api_key):
        """Test default realm value."""
        test_app.add_middleware(CredentialMiddleware, api_key=valid_api_key)

        @test_app.get("/protected")
        async def protected_route(api_key: str = Depends(require_api_key)):
            return {"api_key": api_key}

        client = TestClient(test_app)
        response = client.get("/protected")
        assert response.status_code == 401
        assert 'realm="Access to the protected resource"' in response.headers["WWW-Authenticate"]


class TestRequireAPIKeyMultipleInstances:
    """Test multiple RequireAPIKey instances with different realms."""

    def test_different_realms_on_different_routes(self, test_app, valid_api_key):
        """Test different realms on different routes."""
        test_app.add_middleware(CredentialMiddleware, api_key=valid_api_key)

        @test_app.get("/api")
        async def api_route(api_key: str = Depends(RequireAPIKey("API access"))):
            return {"api_key": api_key}

        @test_app.get("/admin")
        async def admin_route(api_key: str = Depends(RequireAPIKey("Admin area"))):
            return {"api_key": api_key}

        client = TestClient(test_app)

        # Test API route
        response = client.get("/api")
        assert response.status_code == 401
        assert 'realm="API access"' in response.headers["WWW-Authenticate"]

        # Test admin route
        response = client.get("/admin")
        assert response.status_code == 401
        assert 'realm="Admin area"' in response.headers["WWW-Authenticate"]


class TestRequireAPIKeyEdgeCases:
    """Test edge cases and error scenarios."""

    def test_callable_class_behavior(self):
        """Test RequireAPIKey is callable."""
        instance = RequireAPIKey("Test realm")
        assert callable(instance)
        assert instance.realm == "Test realm"

    def test_realm_initialization(self):
        """Test realm initialization."""
        instance = RequireAPIKey()
        assert instance.realm == "Access to the protected resource"

        custom_instance = RequireAPIKey("Custom realm")
        assert custom_instance.realm == "Custom realm"

    def test_multiple_calls_same_instance(self, test_app, valid_api_key):
        """Test same instance can be used multiple times."""
        test_app.add_middleware(CredentialMiddleware, api_key=valid_api_key)

        custom_require = RequireAPIKey("Shared realm")

        @test_app.get("/route1")
        async def route1(api_key: str = Depends(custom_require)):
            _ = api_key  # Dependency injection test
            return {"route": "route1"}

        @test_app.get("/route2")
        async def route2(api_key: str = Depends(custom_require)):
            _ = api_key  # Dependency injection test
            return {"route": "route2"}

        client = TestClient(test_app)

        # Both routes should use the same realm
        response1 = client.get("/route1")
        assert response1.status_code == 401
        assert 'realm="Shared realm"' in response1.headers["WWW-Authenticate"]

        response2 = client.get("/route2")
        assert response2.status_code == 401
        assert 'realm="Shared realm"' in response2.headers["WWW-Authenticate"]

    def test_no_middleware_configured(self, test_app):
        """Test behavior when CredentialMiddleware is not configured."""

        @test_app.get("/protected")
        async def protected_route(api_key: str = Depends(require_api_key)):
            return {"api_key": api_key}

        client = TestClient(test_app)
        response = client.get("/protected")
        assert response.status_code == 401
        assert response.json()["detail"] == "API key required"
