"""Authentication manager for the Daly Energy API.

Handles API key exchange for JWT tokens with automatic caching and refresh.
"""

import time

import httpx

from dalysdk.exceptions import AuthenticationError


class AuthManager:
    """Manages JWT authentication for the Daly Energy API.

    Exchanges workspace + user API keys for a JWT on first request,
    caches the token, and auto-refreshes when the token is within
    1 hour of expiry.
    """

    def __init__(self, workspace_api_key: str, user_api_key: str, base_url: str):
        self._workspace_api_key = workspace_api_key
        self._user_api_key = user_api_key
        self._base_url = base_url
        self._token: str | None = None
        self._token_expiry: float | None = None  # Unix timestamp

    @property
    def token(self) -> str:
        """Return a valid JWT token, refreshing if needed."""
        if self._token is None or self._is_expired():
            self._refresh()
        return self._token  # type: ignore[return-value]

    def _is_expired(self) -> bool:
        """Check whether the current token is expired or close to expiry.

        Returns True if the token expires within the next hour.
        """
        if self._token_expiry is None:
            return True
        return time.time() >= (self._token_expiry - 3600)

    def _refresh(self) -> None:
        """Exchange API keys for a new JWT token.

        Raises:
            AuthenticationError: If the API rejects the credentials.
        """
        url = f"{self._base_url}/auth/token"
        payload = {
            "workspace": self._workspace_api_key,
            "user": self._user_api_key,
        }

        try:
            response = httpx.post(url, json=payload, timeout=10.0)
        except httpx.HTTPError as exc:
            raise AuthenticationError(detail=f"Failed to connect to auth endpoint: {exc}") from exc

        if response.status_code == 401:
            body = _safe_json(response)
            raise AuthenticationError(
                detail=body.get("detail", "Invalid API keys"),
                response_body=body,
            )

        if response.status_code != 200:
            body = _safe_json(response)
            raise AuthenticationError(
                detail=f"Auth request failed with status {response.status_code}: {body.get('detail', '')}",
                response_body=body,
            )

        data = response.json()
        self._token = data.get("token")
        if not self._token:
            raise AuthenticationError(detail="Auth response did not contain a token")

        # Token is valid for 24 hours
        self._token_expiry = time.time() + 86400

    def invalidate(self) -> None:
        """Clear the cached token so the next request triggers a refresh."""
        self._token = None
        self._token_expiry = None


def _safe_json(response: httpx.Response) -> dict:
    """Attempt to parse JSON from a response, returning empty dict on failure."""
    try:
        return response.json()
    except Exception:
        return {}
