"""Carga (y cachea) un modelo GLiNER en el device deseado."""

from __future__ import annotations

from typing import Any

# Cache global: (model_name, device) -> modelo cargado.
_MODEL_CACHE: dict[tuple[str, str], Any] = {}


def _resolve_device(device: str) -> str:
    """Resuelve `device='auto'` a `cuda` o `cpu` segun disponibilidad."""
    if device != "auto":
        return device
    try:
        import torch
    except ImportError:
        return "cpu"
    return "cuda" if torch.cuda.is_available() else "cpu"


def gliner_load_model(
    model_name: str = "urchade/gliner_multi-v2.1",
    device: str = "auto",
) -> Any:
    """Carga un modelo GLiNER con cache por (model_name, device).

    La primera llamada descarga el modelo desde HuggingFace (~200 MB para
    `gliner_multi-v2.1`). Llamadas sucesivas con los mismos parametros
    devuelven la instancia cacheada.

    Args:
        model_name: ID del modelo en HuggingFace Hub.
        device: 'auto' usa CUDA si esta disponible, o 'cpu'/'cuda'/'cuda:N'
            de forma explicita.

    Returns:
        Instancia del modelo GLiNER lista para `predict_entities`.

    Raises:
        ImportError: si la dependencia `gliner` no esta instalada.
            Solucion: `uv pip install gliner` o instalar el extra `nlp`
            del proyecto (`uv pip install -e '.[nlp]'`).
    """
    resolved_device = _resolve_device(device)
    cache_key = (model_name, resolved_device)
    cached = _MODEL_CACHE.get(cache_key)
    if cached is not None:
        return cached

    try:
        from gliner import GLiNER
    except ImportError as exc:
        raise ImportError(
            "gliner no esta instalado. Instalalo con "
            "`uv pip install gliner` o `uv pip install -e '.[nlp]'`."
        ) from exc

    model = GLiNER.from_pretrained(model_name)
    if hasattr(model, "to"):
        model.to(resolved_device)
    _MODEL_CACHE[cache_key] = model
    return model
