"""GoodMemClient and AsyncGoodMemClient — the main entry points."""

from __future__ import annotations

import httpx

from goodmem.api.administration import AdministrationAPI, AsyncAdministrationAPI
from goodmem.api.api_keys import ApiKeysAPI, AsyncApiKeysAPI
from goodmem.api.embedders import AsyncEmbeddersAPI, EmbeddersAPI
from goodmem.api.llms import AsyncLlmsAPI, LlmsAPI
from goodmem.api.memories import AsyncMemoriesAPI, MemoriesAPI
from goodmem.api.ocr import AsyncOcrAPI, OcrAPI
from goodmem.api.rerankers import AsyncRerankersAPI, RerankersAPI
from goodmem.api.spaces import AsyncSpacesAPI, SpacesAPI
from goodmem.api.system import AsyncSystemAPI, SystemAPI
from goodmem.api.users import AsyncUsersAPI, UsersAPI


def _auth_headers(token: str) -> dict[str, str]:
    """Build auth headers: x-api-key for GoodMem API keys, Bearer token otherwise."""
    if token.startswith("gm_"):
        return {"x-api-key": token}
    return {"Authorization": f"Bearer {token}"}


class GoodMemClient:
    """Synchronous GoodMem API client.

    Usage::

        client = GoodMemClient(base_url="http://localhost:8080", token="your-token")

        # Or as context manager (recommended)
        with GoodMemClient(base_url="...", token="...") as client:
            embedder = client.embedders.create(
                display_name="My Embedder",
                model_identifier="text-embedding-3-large",
                api_key="sk-...",
            )
    """

    def __init__(
        self,
        base_url: str,
        token: str,
        *,
        timeout: float = 30.0,
        **kwargs,
    ) -> None:
        self._http = httpx.Client(base_url=base_url, timeout=timeout, **kwargs)
        self._headers = _auth_headers(token)

        # Namespace APIs
        self.embedders = EmbeddersAPI(self._http, self._headers)
        self.rerankers = RerankersAPI(self._http, self._headers)
        self.llms = LlmsAPI(self._http, self._headers)
        self.spaces = SpacesAPI(self._http, self._headers)
        self.memories = MemoriesAPI(self._http, self._headers)
        self.api_keys = ApiKeysAPI(self._http, self._headers)
        self.users = UsersAPI(self._http, self._headers)
        self.ocr = OcrAPI(self._http, self._headers)
        self.system = SystemAPI(self._http, self._headers)
        self.administration = AdministrationAPI(self._http, self._headers)

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

    def __enter__(self) -> GoodMemClient:
        return self

    def __exit__(self, *args) -> None:
        self.close()


class AsyncGoodMemClient:
    """Asynchronous GoodMem API client.

    Usage::

        async with AsyncGoodMemClient(base_url="...", token="...") as client:
            embedder = await client.embedders.create(
                display_name="My Embedder",
                model_identifier="text-embedding-3-large",
                api_key="sk-...",
            )
    """

    def __init__(
        self,
        base_url: str,
        token: str,
        *,
        timeout: float = 30.0,
        **kwargs,
    ) -> None:
        self._http = httpx.AsyncClient(base_url=base_url, timeout=timeout, **kwargs)
        self._headers = _auth_headers(token)

        self.embedders = AsyncEmbeddersAPI(self._http, self._headers)
        self.rerankers = AsyncRerankersAPI(self._http, self._headers)
        self.llms = AsyncLlmsAPI(self._http, self._headers)
        self.spaces = AsyncSpacesAPI(self._http, self._headers)
        self.memories = AsyncMemoriesAPI(self._http, self._headers)
        self.api_keys = AsyncApiKeysAPI(self._http, self._headers)
        self.users = AsyncUsersAPI(self._http, self._headers)
        self.ocr = AsyncOcrAPI(self._http, self._headers)
        self.system = AsyncSystemAPI(self._http, self._headers)
        self.administration = AsyncAdministrationAPI(self._http, self._headers)

    async def close(self) -> None:
        await self._http.aclose()

    async def __aenter__(self) -> AsyncGoodMemClient:
        return self

    async def __aexit__(self, *args) -> None:
        await self.close()
