import os
from typing import Any

import httpx

from zvondb.exceptions import (
    AuthenticationError,
    ConflictError,
    NotFoundError,
    RegistryError,
)


class RegistryClient:
    """Low-level HTTP client for the ML Artifact Registry API."""

    def __init__(
        self,
        base_url: str | None = None,
        api_key: str | None = None,
        timeout: float = 30.0,
    ):
        self._base_url = (base_url or os.environ.get("ZVONDB_URL", "http://localhost:8000")).rstrip("/")
        self._api_key = api_key or os.environ.get("ZVONDB_API_KEY", "")
        self._http = httpx.Client(
            base_url=self._base_url,
            headers={"Authorization": f"Bearer {self._api_key}"},
            timeout=timeout,
        )

    def get(self, path: str, params: dict[str, Any] | None = None) -> Any:
        resp = self._http.get(path, params=self._clean_params(params))
        return self._handle(resp)

    def post(self, path: str, json: dict[str, Any] | None = None) -> Any:
        resp = self._http.post(path, json=json)
        return self._handle(resp)

    def patch(self, path: str, json: dict[str, Any] | None = None) -> Any:
        resp = self._http.patch(path, json=json)
        return self._handle(resp)

    def close(self) -> None:
        self._http.close()

    @staticmethod
    def _clean_params(params: dict[str, Any] | None) -> dict[str, Any] | None:
        if params is None:
            return None
        return {k: v for k, v in params.items() if v is not None}

    @staticmethod
    def _handle(resp: httpx.Response) -> Any:
        if resp.status_code == 401:
            raise AuthenticationError("Invalid API key", status_code=401)
        if resp.status_code == 404:
            detail = resp.json().get("detail", "Not found")
            raise NotFoundError(detail, status_code=404)
        if resp.status_code == 409:
            detail = resp.json().get("detail", "Conflict")
            raise ConflictError(detail, status_code=409)
        if resp.status_code >= 400:
            try:
                detail = resp.json().get("detail", resp.text)
            except Exception:
                detail = resp.text
            raise RegistryError(detail, status_code=resp.status_code)
        if resp.status_code == 204:
            return None
        return resp.json()
