"""JWKS fetching with intelligent caching."""

import time
from typing import Any

import httpx

from ..exceptions import JWKSError


class JWKSClient:
    """Fetches and caches JWKS from vikdata.

    This client fetches JSON Web Key Sets from a configured URL and caches
    them for performance. It supports automatic cache invalidation and
    forced refresh for key rotation scenarios.

    Attributes:
        jwks_url: URL to fetch JWKS from
        cache_ttl: Cache time-to-live in seconds (default: 3600 = 1 hour)
        http_timeout: HTTP request timeout in seconds (default: 10.0)
    """

    def __init__(
        self,
        jwks_url: str,
        cache_ttl: int = 3600,
        http_timeout: float = 10.0,
    ):
        """Initialize JWKS client.

        Args:
            jwks_url: URL to fetch JWKS from (e.g., https://api.vikdata.com/.well-known/jwks.json)
            cache_ttl: How long to cache JWKS in seconds (default: 1 hour)
            http_timeout: HTTP request timeout in seconds
        """
        self.jwks_url = jwks_url
        self.cache_ttl = cache_ttl
        self.http_timeout = http_timeout
        self._cache: dict[str, Any] | None = None
        self._cache_expires: float = 0

    async def get_jwks(self, force_refresh: bool = False) -> dict[str, Any]:
        """Get JWKS, using cache if available.

        Args:
            force_refresh: If True, ignore cache and fetch fresh JWKS

        Returns:
            JWKS dictionary with "keys" array

        Raises:
            JWKSError: If JWKS cannot be fetched or parsed
        """
        now = time.time()

        # Return cached JWKS if valid
        if not force_refresh and self._cache and now < self._cache_expires:
            return self._cache

        try:
            async with httpx.AsyncClient(timeout=self.http_timeout) as client:
                response = await client.get(self.jwks_url)
                response.raise_for_status()
                self._cache = response.json()
                self._cache_expires = now + self.cache_ttl
        except httpx.HTTPStatusError as e:
            raise JWKSError(f"Failed to fetch JWKS: HTTP {e.response.status_code}") from e
        except httpx.RequestError as e:
            raise JWKSError(f"Failed to fetch JWKS: {e}") from e
        except ValueError as e:
            raise JWKSError(f"Invalid JWKS response: {e}") from e

        return self._cache

    def get_key(self, jwks: dict[str, Any], kid: str) -> dict[str, Any]:
        """Get a specific key from JWKS by kid.

        Args:
            jwks: JWKS dictionary with "keys" array
            kid: Key ID to find

        Returns:
            JWK dictionary for the specified kid

        Raises:
            KeyError: If key with specified kid is not found
        """
        keys = jwks.get("keys", [])
        for key in keys:
            if key.get("kid") == kid:
                return key
        raise KeyError(f"Key '{kid}' not found in JWKS")

    def clear_cache(self) -> None:
        """Clear the JWKS cache, forcing next request to fetch fresh data."""
        self._cache = None
        self._cache_expires = 0

    @property
    def is_cached(self) -> bool:
        """Check if JWKS is currently cached and valid."""
        return self._cache is not None and time.time() < self._cache_expires
