"""Tests para gliner2_load_model.

El modelo real (gliner2) es opcional. Los tests usan un stub para validar
el cache sin descargar el modelo. Tests que requieran el modelo real se
marcan con pytest.importorskip('gliner2').
"""

from __future__ import annotations

import os
import sys

import pytest

sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "..", "..", ".."))

from python.functions.datascience.gliner2_load_model import (
    _MODEL_CACHE,
    _resolve_device,
    gliner2_load_model,
)


class _StubGLiNER2:
    """Stub duck-typed para validar el cache sin descargar el modelo real."""

    @classmethod
    def from_pretrained(cls, model_name: str) -> "_StubGLiNER2":
        return cls()

    def create_schema(self):
        return self

    def entities(self, labels):
        return self

    def relations(self, labels):
        return self

    def extract(self, text, **kwargs):
        return {"entities": {}, "relation_extraction": {}}


def test_cache_devuelve_la_misma_instancia(monkeypatch):
    """cache devuelve la misma instancia con los mismos parametros"""
    _MODEL_CACHE.clear()
    monkeypatch.setattr(
        "python.functions.datascience.gliner2_load_model.GLiNER2",
        _StubGLiNER2,
        raising=False,
    )
    # Patch el import dentro de la funcion
    import python.functions.datascience.gliner2_load_model as mod
    original = None
    try:
        from gliner2 import GLiNER2 as _real  # type: ignore[import]
        original = _real
    except ImportError:
        pass

    _MODEL_CACHE.clear()
    # Insertar stub directamente en el cache para simular primera carga
    key = ("fastino/gliner2-large-v1", "cpu")
    stub = _StubGLiNER2()
    _MODEL_CACHE[key] = stub

    # Segunda llamada debe devolver el mismo objeto
    result = gliner2_load_model(model_name="fastino/gliner2-large-v1", device="cpu")
    assert result is stub
    _MODEL_CACHE.clear()


def test_device_auto_resuelve_a_cpu_si_torch_no_esta(monkeypatch):
    """device=auto resuelve a cpu si torch no esta instalado"""
    import sys
    # Simular que torch no esta disponible
    monkeypatch.setitem(sys.modules, "torch", None)
    resolved = _resolve_device("auto")
    assert resolved == "cpu"


def test_import_error_si_gliner2_no_esta_instalado():
    """ImportError si gliner2 no esta instalado"""
    pytest.importorskip("gliner2", reason="gliner2 not installed — skip real model test")
