"""
matrice_vss.inference
=====================
Async HTTP clients for text-generation (LLM) and vision-language (VLM)
inference backends.

Both clients are thin wrappers around ``httpx.AsyncClient`` and expose a
uniform interface (``generate``, ``health_check``, ``close``).  Singleton
accessors (``get_llm``, ``get_vlm``) are provided so callers never manage
client lifecycle manually.

LLM backends supported
-----------------------
* **Ollama** (default) — :class:`OllamaClient` targeting
  ``/api/generate`` on the Ollama HTTP API.
* **vLLM** — :class:`VLLMTextClient` targeting the OpenAI-compatible
  ``/chat/completions`` endpoint.

The active backend is selected via ``VSS_LLM__USE_VLLM`` (default ``false``).

VLM backend
-----------
:class:`VLMClient` — Cosmos-Reason2-8B served by vLLM's OpenAI-compatible
API.  Supports multi-image inputs encoded as base64 strings.

Usage
-----
.. code-block:: python

    # Sync factory — returns already-constructed client, do NOT await
    llm = get_llm()
    vlm = get_vlm()

    # Async methods
    answer  = await llm.generate("How many alerts yesterday?")
    healthy = await vlm.health_check()

Important
---------
``get_llm()`` and ``get_vlm()`` are **synchronous** functions.  They return
the client object directly (no ``await``).  The methods on the returned client
(``generate``, ``health_check``) are ``async`` and must be awaited.
"""

from __future__ import annotations

from typing import TYPE_CHECKING


def __getattr__(name: str):  # noqa: N807
    """Lazy-load public symbols from child modules on first access."""
    import importlib

    _symbol_map: dict[str, str] = {
        # inference.llm_client
        "BaseLLMClient": "llm_client",
        "OllamaClient": "llm_client",
        "VLLMTextClient": "llm_client",
        "get_llm_client": "llm_client",
        "get_llm": "llm_client",
        # inference.vlm_client
        "VLMClient": "vlm_client",
        "get_vlm": "vlm_client",
    }

    if name in _symbol_map:
        module = importlib.import_module(
            f".{_symbol_map[name]}", package=__name__
        )
        value = getattr(module, name)
        globals()[name] = value
        return value

    raise AttributeError(f"module {__name__!r} has no attribute {name!r}")


if TYPE_CHECKING:  # pragma: no cover
    from .llm_client import (  # noqa: F401
        BaseLLMClient,
        OllamaClient,
        VLLMTextClient,
        get_llm,
        get_llm_client,
    )
    from .vlm_client import VLMClient, get_vlm  # noqa: F401

__all__: list[str] = [
    # llm_client
    "BaseLLMClient",
    "OllamaClient",
    "VLLMTextClient",
    "get_llm_client",
    "get_llm",
    # vlm_client
    "VLMClient",
    "get_vlm",
]
