"""Ejecutar junto a agente_stock.py: python3 -m unittest -v test_agente_stock.py"""
import copy
import json
import unittest
from types import SimpleNamespace as Item
from agente_stock import ejecutar, responder


class ClienteSimulado:
    def __init__(self, respuestas):
        self.responses = self
        self.respuestas = iter(respuestas)
        self.entradas = []

    def create(self, **kwargs):
        self.entradas.append(copy.deepcopy(kwargs["input"]))
        return next(self.respuestas)


def llamada(nombre="consultar_stock", argumentos='{"sku":"A-100"}'):
    return Item(type="function_call", name=nombre, arguments=argumentos, call_id="call_1")


class PruebasAgente(unittest.TestCase):
    def test_stock_y_desconocido_son_distintos(self):
        self.assertEqual(ejecutar("consultar_stock", '{"sku":"C-300"}')["stock"], 0)
        self.assertEqual(ejecutar("consultar_stock", '{"sku":"X"}')["error"], "sku_desconocido")

    def test_rechaza_nombre_json_y_schema_invalidos(self):
        for nombre, argumentos in [("borrar", "{}"), ("consultar_stock", "{"),
                                    ("consultar_stock", "[]"), ("consultar_stock", '{"sku":3}'),
                                    ("consultar_stock", '{"sku":"A-100","admin":true}')]:
            self.assertIn("error", ejecutar(nombre, argumentos))

    def test_preserva_llamada_y_devuelve_output_en_nivel_superior(self):
        cliente = ClienteSimulado([
            Item(output=[llamada()], output_text=""),
            Item(output=[], output_text="Hay 23 unidades."),
        ])
        self.assertEqual(responder(cliente, "Stock", "simulado"), "Hay 23 unidades.")
        historial = cliente.entradas[1]
        self.assertEqual(historial[1].call_id, "call_1")
        self.assertEqual(historial[2]["type"], "function_call_output")
        self.assertNotIn("role", historial[2])
        self.assertEqual(json.loads(historial[2]["output"])["stock"], 23)

    def test_limite_de_pasos(self):
        cliente = ClienteSimulado([Item(output=[llamada()], output_text="")] * 2)
        with self.assertRaisesRegex(RuntimeError, "Límite"):
            responder(cliente, "Stock", "simulado", max_pasos=2)
        self.assertEqual(len(cliente.entradas), 2)

    def test_salida_vacia(self):
        cliente = ClienteSimulado([Item(output=[], output_text="")])
        with self.assertRaisesRegex(RuntimeError, "vacía"):
            responder(cliente, "Stock", "simulado")

    def test_tope_llamadas(self):
        cliente = ClienteSimulado([Item(output=[llamada()] * 5, output_text="")])
        with self.assertRaisesRegex(RuntimeError, "Demasiadas"):
            responder(cliente, "Stock", "simulado")


if __name__ == "__main__":
    unittest.main()
