"""
03 - Tool calling 100% soberano: el modelo busca a través de un SearXNG local.

Idéntico a 02_busqueda_web.py salvo una cosa: la función buscar_web ya no llama
a DuckDuckGo, sino a una instancia local de SearXNG en http://localhost:8888.

Eso demuestra lo importante del tool calling: el modelo y el bucle NO cambian.
Solo cambia el CUERPO de la herramienta. Hoy SearXNG; mañana podría ser una
base de datos de expedientes o cualquier API interna. El patrón es el mismo.

Requisito: SearXNG levantado ->  cd searxng && docker compose up -d
"""

import requests
import ollama

MODELO = "qwen2.5:14b-instruct-q4_K_M"
SEARXNG_URL = "http://localhost:8888/search"


# --- La función real: ahora pega a SearXNG, todo dentro de casa -----------------

def buscar_web(query: str) -> str:
    print(f"   [Python consulta SearXNG local] '{query}'")
    resp = requests.get(
        SEARXNG_URL,
        params={"q": query, "format": "json"},
        timeout=20,
    )
    resp.raise_for_status()
    resultados = resp.json().get("results", [])[:5]
    if not resultados:
        return "No se encontraron resultados."
    return "\n\n".join(
        f"[{i+1}] {r.get('title','')}\n{r.get('content','')}\nFuente: {r.get('url','')}"
        for i, r in enumerate(resultados)
    )


FUNCIONES = {"buscar_web": buscar_web}

TOOLS = [
    {
        "type": "function",
        "function": {
            "name": "buscar_web",
            "description": (
                "Busca información actualizada en internet a través de un metabuscador "
                "privado. Úsala SIEMPRE que la pregunta trate sobre hechos recientes, "
                "fechas, versiones, precios, noticias o algo que no sepas con certeza."
            ),
            "parameters": {
                "type": "object",
                "properties": {
                    "query": {
                        "type": "string",
                        "description": "Términos de búsqueda, concisos.",
                    }
                },
                "required": ["query"],
            },
        },
    }
]

SYSTEM = (
    "Eres un asistente útil. Si no estás seguro de un dato o puede haber cambiado "
    "tras tu entrenamiento, USA la herramienta buscar_web antes de responder. "
    "Cita las fuentes (URLs) que uses en tu respuesta final."
)


def responder(pregunta: str, max_turnos: int = 5):
    messages = [
        {"role": "system", "content": SYSTEM},
        {"role": "user", "content": pregunta},
    ]
    for _ in range(max_turnos):
        respuesta = ollama.chat(model=MODELO, messages=messages, tools=TOOLS)
        messages.append(respuesta.message)
        if not respuesta.message.tool_calls:
            print("\nRESPUESTA FINAL:\n")
            print(respuesta.message.content)
            return
        for tc in respuesta.message.tool_calls:
            funcion = FUNCIONES.get(tc.function.name)
            resultado = (
                funcion(**tc.function.arguments)
                if funcion else f"Error: herramienta desconocida '{tc.function.name}'"
            )
            messages.append({
                "role": "tool",
                "name": tc.function.name,
                "content": str(resultado),
            })
    print("Se alcanzó el máximo de turnos sin respuesta final.")


if __name__ == "__main__":
    responder("¿Qué versión estable de Python es la más reciente y cuándo salió?")
