"""Async HTTP client for the TMS REST API."""
from __future__ import annotations

import json
import os

import httpx


class TmsApiClient:
    """Thin async wrapper around the TMS backend API."""

    def __init__(self):
        self.base_url = os.getenv("TMS_API_URL", "http://localhost:8000").rstrip("/")
        self._token: str | None = None
        self._client: httpx.AsyncClient | None = None

    async def _ensure_client(self) -> httpx.AsyncClient:
        if self._client is None or self._client.is_closed:
            self._client = httpx.AsyncClient(base_url=self.base_url, timeout=30.0)
        return self._client

    def set_token(self, token: str):
        self._token = token

    def _headers(self) -> dict[str, str]:
        headers = {"Content-Type": "application/json"}
        if self._token:
            headers["Authorization"] = f"Bearer {self._token}"
        return headers

    async def request(
        self, method: str, path: str, *, json_body: dict | None = None, params: dict | None = None
    ) -> dict | list | None:
        """Make an API request and return parsed JSON, or a human-readable error string."""
        client = await self._ensure_client()
        try:
            resp = await client.request(
                method, path, headers=self._headers(), json=json_body, params=params
            )
        except httpx.ConnectError:
            raise ApiError(f"Cannot connect to TMS API at {self.base_url}. Is the backend running?")

        if resp.status_code == 204:
            return None

        if resp.status_code == 401:
            raise ApiError(
                "Authentication failed. Your token may have expired. "
                "Use the tms_login tool to re-authenticate."
            )
        if resp.status_code == 403:
            detail = _extract_detail(resp)
            raise ApiError(f"Permission denied: {detail}")
        if resp.status_code == 404:
            detail = _extract_detail(resp)
            raise ApiError(f"Not found: {detail}")
        if resp.status_code == 409:
            detail = _extract_detail(resp)
            raise ApiError(f"Conflict: {detail}")
        if resp.status_code == 422:
            detail = _extract_detail(resp)
            raise ApiError(f"Validation error: {detail}")
        if resp.status_code >= 500:
            raise ApiError(f"TMS API server error ({resp.status_code}). Is the backend healthy?")
        if resp.status_code >= 400:
            detail = _extract_detail(resp)
            raise ApiError(f"API error {resp.status_code}: {detail}")

        return resp.json()

    async def get(self, path: str, **params) -> dict | list | None:
        clean = {k: v for k, v in params.items() if v is not None}
        return await self.request("GET", path, params=clean or None)

    async def post(self, path: str, body: dict | None = None) -> dict | list | None:
        return await self.request("POST", path, json_body=body)

    async def put(self, path: str, body: dict | None = None) -> dict | list | None:
        return await self.request("PUT", path, json_body=body)

    async def delete(self, path: str) -> dict | list | None:
        return await self.request("DELETE", path)


class ApiError(Exception):
    """Raised when the TMS API returns an error. Message is human-readable."""
    pass


def _extract_detail(resp: httpx.Response) -> str:
    try:
        data = resp.json()
        if isinstance(data, dict) and "detail" in data:
            detail = data["detail"]
            if isinstance(detail, list):
                return "; ".join(
                    f"{e.get('loc', ['?'])[-1]}: {e.get('msg', '?')}" for e in detail
                )
            return str(detail)
        return json.dumps(data)
    except Exception:
        return resp.text[:200]


# Module-level singleton
client = TmsApiClient()
