"""AgentAuth Python SDK client."""
from typing import Any

import httpx

from agentauth.exceptions import AgentAuthError, AuthenticationError, RateLimitError, TokenError
from agentauth.models import ProxyResponse, ServiceToken


class ClavisClient:
    """Dead-simple AgentAuth client. Understand the full API in 5 minutes.

    Usage::

        client = AgentAuthClient(api_key="your-jwt-token", base_url="https://your-agentauth.com")

        # Get a token for a service
        token = await client.get_token("kalshi")
        print(token.access_token)  # ready to use

        # Or let AgentAuth proxy the whole request
        response = await client.proxy("kalshi", "GET", "/trade-api/v2/markets")
    """

    def __init__(self, api_key: str, base_url: str = "http://localhost:8000") -> None:
        self._base_url = base_url.rstrip("/")
        self._headers = {"Authorization": f"Bearer {api_key}"}

    async def get_token(self, service_name: str) -> ServiceToken:
        """Get a valid token for a registered service (auto-refreshes if expired).

        Args:
            service_name: The service name you used when registering (e.g., 'kalshi').

        Returns:
            ServiceToken with a ready-to-use access_token.

        Raises:
            TokenError: If no token can be obtained.
        """
        async with httpx.AsyncClient() as http:
            resp = await http.get(
                f"{self._base_url}/v1/tokens/{service_name}",
                headers=self._headers,
                timeout=30,
            )
            self._raise_for_status(resp)
            return ServiceToken(**resp.json())

    async def proxy(
        self,
        service_name: str,
        method: str,
        path: str,
        params: dict[str, Any] | None = None,
        body: dict[str, Any] | None = None,
        headers: dict[str, str] | None = None,
    ) -> ProxyResponse:
        """Proxy a request through AgentAuth (adds auth, handles rate limits).

        Args:
            service_name: The service to call (e.g., 'kalshi').
            method: HTTP method (GET, POST, etc.).
            path: API path on the target service (e.g., '/trade-api/v2/markets').
            params: Optional query parameters.
            body: Optional JSON request body.
            headers: Optional extra headers.

        Returns:
            ProxyResponse with status_code, headers, and body.

        Raises:
            RateLimitError: If the service rate limit is exceeded.
            AgentAuthError: For other errors.
        """
        async with httpx.AsyncClient() as http:
            resp = await http.post(
                f"{self._base_url}/v1/proxy/{service_name}",
                headers=self._headers,
                json={"method": method, "path": path, "params": params, "body": body, "headers": headers},
                timeout=60,
            )
            self._raise_for_status(resp)
            data = resp.json()
            return ProxyResponse(
                **data,
                rate_limit_remaining=int(resp.headers.get("X-RateLimit-Remaining", 0)),
            )

    def _raise_for_status(self, resp: httpx.Response) -> None:
        """Convert HTTP errors to AgentAuth exceptions with helpful messages."""
        if resp.status_code == 401:
            raise AuthenticationError("Invalid API key. Get a new token at POST /v1/auth/login.", status_code=401)
        if resp.status_code == 429:
            retry_after = int(resp.headers.get("Retry-After", 1))
            raise RateLimitError(
                resp.json().get("detail", "Rate limit exceeded."),
                retry_after=retry_after,
            )
        if resp.status_code == 503:
            raise TokenError(resp.json().get("detail", "Token unavailable."), status_code=503)
        if resp.status_code >= 400:
            detail = resp.json().get("detail", resp.text) if resp.content else resp.text
            raise AgentAuthError(detail, status_code=resp.status_code)
