"""Agente simulado para servidor.py. Cada ciclo avanza un segundo lógico."""
import argparse
from copy import deepcopy
import json
import os
import time
from urllib.error import HTTPError, URLError
from urllib.request import Request, urlopen
from uuid import uuid4
from nucleo import Dispositivo


def intercambiar(ruta, token, datos=None):
    contenido = None if datos is None else json.dumps(datos, allow_nan=False).encode("utf-8")
    peticion = Request("http://127.0.0.1:8765" + ruta, data=contenido,
                       headers={"Authorization": "Bearer " + token, "Content-Type": "application/json"})
    with urlopen(peticion, timeout=0.5) as respuesta:
        return json.loads(respuesta.read(16384))


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("--ciclos", type=int, default=30)
    parser.add_argument("--sin-red", type=int, default=0, help="Ciclos iniciales sin intercambios")
    args = parser.parse_args()
    if not 1 <= args.ciclos <= 10000 or not 0 <= args.sin_red <= args.ciclos:
        parser.error("Ciclos entre 1 y 10000; sin-red entre 0 y ciclos")
    token = os.environ.get("IOT_DEVICE_TOKEN", "")
    if len(token) < 16:
        raise SystemExit("Definí IOT_DEVICE_TOKEN con el valor usado por el servidor.")
    equipo = Dispositivo(boot=uuid4().hex)
    valores = [24, 29, 27, 25, None, 30, 27, 25]
    for paso in range(args.ciclos):
        inicio = time.monotonic()
        guardada = equipo.medir(valores[paso % len(valores)])
        estado = "sin red simulada"
        if paso >= args.sin_red:
            try:
                equipo.configurar(intercambiar("/api/config", token))
                # Presupuesto: como máximo dos registros por ciclo.
                for _ in range(2):
                    if not equipo.cola:
                        break
                    primero = deepcopy(equipo.cola[0])
                    ack = intercambiar("/api/muestras", token, primero)
                    if (ack.get("boot"), ack.get("seq")) != (primero["boot"], primero["seq"]):
                        raise ValueError("Confirmación no corresponde al registro")
                    equipo.confirmar(ack["boot"], ack["seq"])
                estado = "intercambio completado"
            except HTTPError as error:
                estado = f"HTTP {error.code}; conserva cola y configuración válida"
                error.close()
            except (URLError, TimeoutError, OSError, ValueError):
                estado = "intercambio incompleto; conserva pendientes"
        print(f"t={equipo.ahora:3} lectura={str(equipo.valor):4} salida={int(equipo.salida)} "
              f"config={equipo.config['version']} cola={len(equipo.cola)}/3 "
              f"descartes={equipo.descartes} guardada={guardada} | {estado}")
        time.sleep(max(0, 1 - (time.monotonic() - inicio)))
    print("Fin del agente: la cola y la configuración local están en RAM y se pierden al cerrarlo.")


if __name__ == "__main__":
    main()
