"""Async HTTP client with automatic retry logic and auth helpers."""

# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/07_utils_api.ipynb.

# %% ../nbs/07_utils_api.ipynb 2
from __future__ import annotations
import httpx
from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_exception
from typing import Optional, Dict, Any
import logging
from nbdev.showdoc import show_doc

logger = logging.getLogger(__name__)

# Custom retry condition: only retry on 429 or 500+ status codes
def _should_retry_on_status(exception):
    """Only retry on 429 rate limit or 500+ server errors"""
    if isinstance(exception, httpx.HTTPStatusError):
        return exception.response.status_code == 429 or exception.response.status_code >= 500
    if isinstance(exception, httpx.RequestError):
        return True  # Always retry network errors
    return False

# %% auto 0
__all__ = ['logger', 'AsyncAPIClient', 'bearer_token_auth', 'api_key_auth', 'oauth_token_auth']

# %% ../nbs/07_utils_api.ipynb 5
class AsyncAPIClient:
    """Async HTTP client with retry logic for external API integrations."""
    
    def __init__(
        self, 
        base_url: str,
        auth_headers: dict = None,
        timeout: int = 30
    ):
        """Initialize client with base URL, optional auth headers, and timeout."""
        self.base_url = base_url.rstrip('/')
        self.auth_headers = auth_headers or {}
        self.timeout = timeout
        self.client = None
    
    async def __aenter__(self):
        """Async context manager entry - creates httpx client."""
        self.client = httpx.AsyncClient(
            base_url=self.base_url,
            headers=self.auth_headers,
            timeout=self.timeout
        )
        return self
    
    async def __aexit__(self, exc_type, exc_val, exc_tb):
        """Async context manager exit - closes httpx client."""
        if self.client:
            await self.client.aclose()
    
    @retry(
        stop=stop_after_attempt(3),
        wait=wait_exponential(multiplier=1, min=2, max=10),
        retry=retry_if_exception(_should_retry_on_status),
        reraise=True
    )
    async def request(
        self,
        method: str,
        endpoint: str,
        params: dict = None,
        json: dict = None,
        headers: dict = None
    ) -> httpx.Response:
        """Execute HTTP request with automatic retry on 429/500+ errors."""
        if not self.client:
            raise RuntimeError("Client not initialized. Use 'async with' context manager.")
        
        request_headers = {**self.auth_headers, **(headers or {})}
        
        response = await self.client.request(
            method=method,
            url=endpoint,
            params=params,
            json=json,
            headers=request_headers
        )
        response.raise_for_status()
        return response
    
    async def get_json(
        self,
        endpoint: str,
        params: dict = None
    ) -> Dict[str, Any]:
        """Convenience GET that returns parsed JSON."""
        response = await self.request('GET', endpoint, params=params)
        return response.json()

# %% ../nbs/07_utils_api.ipynb 10
def bearer_token_auth(token: str) -> dict:
    """Generate Bearer token authentication header."""
    return {'Authorization': f'Bearer {token}'}


def api_key_auth(api_key: str, header_name: str = 'X-API-Key') -> dict:
    """Generate API key header with customizable header name."""
    return {header_name: api_key}


def oauth_token_auth(access_token: str) -> dict:
    """Generate OAuth 2.0 access token header (alias for bearer_token_auth)."""
    return bearer_token_auth(access_token)
