"""Low-level HTTP client wrapping httpx with auth and error mapping."""

from __future__ import annotations

from typing import Any

import httpx as _httpx

from mcpgateway_sdk._config import SDKConfig
from mcpgateway_sdk._exceptions import GatewayError, error_from_response


class HTTPClient:
    """Async HTTP client that injects auth headers and maps errors to exceptions."""

    def __init__(self, config: SDKConfig) -> None:
        self._config = config
        self._client = _httpx.AsyncClient(
            base_url=config.url,
            timeout=config.timeout,
        )

    def _build_headers(self, extra: dict[str, str] | None = None) -> dict[str, str]:
        """Build request headers with auth token and optional extras."""
        headers = {"Authorization": f"Bearer {self._config.api_key}"}
        if extra:
            headers.update(extra)
        return headers

    async def request(
        self,
        method: str,
        path: str,
        *,
        params: dict[str, Any] | None = None,
        json: Any = None,
        content: bytes | None = None,
        headers: dict[str, str] | None = None,
        files: Any = None,
        data: dict[str, str] | None = None,
    ) -> Any:
        """Send an HTTP request and return parsed JSON, or raise on error."""
        try:
            resp = await self._client.request(
                method,
                path,
                params=params,
                json=json,
                content=content,
                headers=self._build_headers(headers),
                files=files,
                data=data,
            )
        except _httpx.TimeoutException as exc:
            raise GatewayError(
                status_code=0, message=f"Request timed out: {method} {path}"
            ) from exc
        except _httpx.ConnectError as exc:
            raise GatewayError(
                status_code=0,
                message=f"Cannot connect to {self._config.url}: {exc}",
            ) from exc
        except _httpx.HTTPError as exc:
            raise GatewayError(
                status_code=0, message=f"Network error: {method} {path}: {exc}"
            ) from exc

        if resp.is_success:
            if resp.status_code == 204:
                return None
            return resp.json()

        try:
            body = resp.json()
        except (ValueError, UnicodeDecodeError):
            body = {"detail": resp.content.decode("utf-8", errors="replace")}
        raise error_from_response(resp.status_code, body)

    async def request_raw(
        self,
        method: str,
        path: str,
        *,
        params: dict[str, Any] | None = None,
        headers: dict[str, str] | None = None,
    ) -> bytes:
        """Send an HTTP request and return raw bytes, or raise on error."""
        try:
            resp = await self._client.request(
                method,
                path,
                params=params,
                headers=self._build_headers(headers),
            )
        except _httpx.TimeoutException as exc:
            raise GatewayError(
                status_code=0, message=f"Request timed out: {method} {path}"
            ) from exc
        except _httpx.ConnectError as exc:
            raise GatewayError(
                status_code=0,
                message=f"Cannot connect to {self._config.url}: {exc}",
            ) from exc
        except _httpx.HTTPError as exc:
            raise GatewayError(
                status_code=0, message=f"Network error: {method} {path}: {exc}"
            ) from exc

        if resp.is_success:
            return resp.content

        try:
            body = resp.json()
        except (ValueError, UnicodeDecodeError):
            body = {"detail": resp.content.decode("utf-8", errors="replace")}
        raise error_from_response(resp.status_code, body)

    async def close(self) -> None:
        """Close the underlying httpx client."""
        await self._client.aclose()
