"""
01 - Tool calling al desnudo (sin internet).

Objetivo: VER el baile entre el programa y el modelo.
Se usa una herramienta tonta -una calculadora- para que no haya magia oculta.

El flujo es SIEMPRE el mismo, da igual que la herramienta sea sumar o buscar en Google:

    1. El programa describe las herramientas que existen (nombre, para qué sirven, parámetros).
    2. Se le pasa la pregunta del usuario + esa lista de herramientas al modelo.
    3. El modelo NO ejecuta nada. Si cree que necesita una herramienta, devuelve
       un JSON: "llama a 'sumar' con a=25, b=17".
    4. El programa ejecuta la función de verdad.
    5. Se le devuelve el resultado al modelo (como un mensaje de rol 'tool').
    6. El modelo redacta la respuesta final en lenguaje natural.
"""

import ollama

MODELO = "qwen2.5:14b-instruct-q4_K_M"


# --- PASO 0: las funciones reales de Python que el modelo podrá "pedir" ---------

def sumar(a: int, b: int) -> int:
    print(f"   [Python ejecuta de verdad] sumar({a}, {b})")
    return a + b


# Mapa nombre-de-herramienta -> función real. Se usa para despachar.
FUNCIONES = {"sumar": sumar}


# --- PASO 1: describir las herramientas al modelo -------------------------------
# Esto es un "menú". El modelo lee la descripción y los parámetros para decidir
# si la necesita y con qué valores llamarla. La descripción IMPORTA mucho:
# es lo único que el modelo tiene para entender cuándo usarla.

TOOLS = [
    {
        "type": "function",
        "function": {
            "name": "sumar",
            "description": "Suma dos números enteros y devuelve el resultado.",
            "parameters": {
                "type": "object",
                "properties": {
                    "a": {"type": "integer", "description": "Primer sumando"},
                    "b": {"type": "integer", "description": "Segundo sumando"},
                },
                "required": ["a", "b"],
            },
        },
    }
]


def main():
    # El historial de la conversación. Se van añadiendo mensajes aquí.
    messages = [
        {"role": "user", "content": "¿Cuánto es 25 + 17? Usa la herramienta."}
    ]

    print("PASO 2: se envía la pregunta + herramientas al modelo...")
    respuesta = ollama.chat(model=MODELO, messages=messages, tools=TOOLS)
    messages.append(respuesta.message)  # se guarda lo que respondió el modelo

    # PASO 3: ¿el modelo ha pedido usar una herramienta?
    if not respuesta.message.tool_calls:
        print("El modelo respondió directamente, sin herramientas:")
        print(respuesta.message.content)
        return

    print("PASO 3: el modelo NO contesta, pide ejecutar herramientas:")
    for tc in respuesta.message.tool_calls:
        print(f"   -> quiere llamar a '{tc.function.name}' con {dict(tc.function.arguments)}")

        # PASO 4: el código ejecuta la función real
        funcion = FUNCIONES[tc.function.name]
        resultado = funcion(**tc.function.arguments)

        # PASO 5: se devuelve el resultado al modelo como mensaje 'tool'
        messages.append({
            "role": "tool",
            "name": tc.function.name,
            "content": str(resultado),
        })

    # PASO 6: el modelo redacta la respuesta final ya con el resultado en mano
    print("\nPASO 6: el modelo redacta la respuesta final con el resultado...")
    final = ollama.chat(model=MODELO, messages=messages, tools=TOOLS)
    print("\nRESPUESTA FINAL:")
    print(final.message.content)


if __name__ == "__main__":
    main()
