"""HTTP transport for the mailbot Python SDK."""

import asyncio
import time
from typing import Any, Dict, Optional

import httpx

from .exceptions import AuthError, ComplianceError, MailBotError, NotFoundError, RateLimitError


class HttpClient:
    """Sync and async HTTP transport wrapper."""

    def __init__(
        self,
        api_key: str,
        base_url: str = "https://agentmail.omyop.com/v1",
        timeout: float = 30.0,
        max_retries: int = 3,
    ) -> None:
        """Create sync and async HTTP clients for the mailbot API."""

        self._headers = {"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"}
        self._base_url = base_url.rstrip("/")
        self._timeout = timeout
        self._max_retries = max_retries
        self._client = httpx.Client(timeout=timeout, headers=self._headers)
        self._async_client = httpx.AsyncClient(timeout=timeout, headers=self._headers)

    def close(self) -> None:
        """Close the sync HTTP client."""

        self._client.close()

    async def aclose(self) -> None:
        """Close the async HTTP client."""

        await self._async_client.aclose()

    def request(
        self,
        method: str,
        path: str,
        *,
        params: Optional[Dict[str, Any]] = None,
        json: Any = None,
    ) -> Any:
        """Perform a synchronous API request."""

        for attempt in range(self._max_retries + 1):
            response = self._client.request(method, f"{self._base_url}{path}", params=params, json=json)
            if response.status_code < 500 or attempt == self._max_retries:
                return self._handle_response(response)
            time.sleep(0.25 * (2 ** attempt))
        raise MailBotError("Request failed after retries")

    async def arequest(
        self,
        method: str,
        path: str,
        *,
        params: Optional[Dict[str, Any]] = None,
        json: Any = None,
    ) -> Any:
        """Perform an asynchronous API request."""

        for attempt in range(self._max_retries + 1):
            response = await self._async_client.request(method, f"{self._base_url}{path}", params=params, json=json)
            if response.status_code < 500 or attempt == self._max_retries:
                return self._handle_response(response)
            await asyncio.sleep(0.25 * (2 ** attempt))
        raise MailBotError("Request failed after retries")

    def _handle_response(self, response: httpx.Response) -> Any:
        """Convert an HTTP response into data or a typed exception."""

        if response.status_code == 401:
            raise AuthError(response.text)
        if response.status_code == 404:
            raise NotFoundError(response.text)
        if response.status_code == 422:
            raise ComplianceError(response.text)
        if response.status_code == 429:
            raise RateLimitError(response.text)
        if response.status_code >= 400:
            raise MailBotError(response.text)
        return response.json()
