"""Tests for JWKS client."""

import pytest
from pytest_httpx import HTTPXMock

from vikdata_auth.jwt import JWKSClient
from vikdata_auth.exceptions import JWKSError


class TestJWKSClient:
    """Tests for JWKSClient."""

    @pytest.fixture
    def jwks_url(self):
        return "https://api.vikdata.com/.well-known/jwks.json"

    @pytest.fixture
    def client(self, jwks_url):
        return JWKSClient(jwks_url=jwks_url, cache_ttl=3600)

    @pytest.mark.asyncio
    async def test_fetch_jwks(self, client, jwks_url, jwks, httpx_mock: HTTPXMock):
        """Successfully fetch JWKS."""
        httpx_mock.add_response(url=jwks_url, json=jwks)

        result = await client.get_jwks()

        assert result == jwks
        assert "keys" in result
        assert len(result["keys"]) == 1

    @pytest.mark.asyncio
    async def test_cache_jwks(self, client, jwks_url, jwks, httpx_mock: HTTPXMock):
        """JWKS is cached after first fetch."""
        httpx_mock.add_response(url=jwks_url, json=jwks)

        # First call fetches
        result1 = await client.get_jwks()

        # Second call uses cache (no additional HTTP request)
        result2 = await client.get_jwks()

        assert result1 == result2
        assert len(httpx_mock.get_requests()) == 1  # Only one HTTP call

    @pytest.mark.asyncio
    async def test_force_refresh(self, client, jwks_url, jwks, httpx_mock: HTTPXMock):
        """Force refresh bypasses cache."""
        httpx_mock.add_response(url=jwks_url, json=jwks)

        # First call fetches
        await client.get_jwks()

        # Force refresh fetches again
        httpx_mock.add_response(url=jwks_url, json=jwks)
        await client.get_jwks(force_refresh=True)

        assert len(httpx_mock.get_requests()) == 2  # Two HTTP calls

    @pytest.mark.asyncio
    async def test_get_key_by_kid(self, client, jwks_url, jwks, kid, httpx_mock: HTTPXMock):
        """Get specific key from JWKS by kid."""
        httpx_mock.add_response(url=jwks_url, json=jwks)

        fetched_jwks = await client.get_jwks()
        key = client.get_key(fetched_jwks, kid)

        assert key["kid"] == kid
        assert key["kty"] == "RSA"
        assert key["alg"] == "RS256"

    @pytest.mark.asyncio
    async def test_get_key_not_found(self, client, jwks_url, jwks, httpx_mock: HTTPXMock):
        """KeyError raised when kid not found."""
        httpx_mock.add_response(url=jwks_url, json=jwks)

        fetched_jwks = await client.get_jwks()

        with pytest.raises(KeyError, match="unknown-kid"):
            client.get_key(fetched_jwks, "unknown-kid")

    @pytest.mark.asyncio
    async def test_http_error(self, client, jwks_url, httpx_mock: HTTPXMock):
        """JWKSError raised on HTTP error."""
        httpx_mock.add_response(url=jwks_url, status_code=500)

        with pytest.raises(JWKSError, match="HTTP 500"):
            await client.get_jwks()

    @pytest.mark.asyncio
    async def test_invalid_json(self, client, jwks_url, httpx_mock: HTTPXMock):
        """JWKSError raised on invalid JSON."""
        httpx_mock.add_response(url=jwks_url, text="not json")

        with pytest.raises(JWKSError, match="Invalid JWKS"):
            await client.get_jwks()

    def test_clear_cache(self, client, jwks):
        """clear_cache removes cached JWKS."""
        client._cache = jwks
        client._cache_expires = 9999999999

        assert client.is_cached is True

        client.clear_cache()

        assert client.is_cached is False
        assert client._cache is None

    def test_is_cached_property(self, client, jwks):
        """is_cached property reflects cache state."""
        assert client.is_cached is False

        client._cache = jwks
        client._cache_expires = 9999999999

        assert client.is_cached is True
