"""Helper compartido por los tests de los builders de workflow ComfyUI.

Valida la invariante del "API format": un dict de nodos numerados, cada uno con
`class_type` + `inputs`, donde las conexiones entre nodos son listas
`[node_id, output_index]` que referencian un node_id existente.
"""


def assert_api_format(wf):
    """Comprueba que `wf` es un workflow ComfyUI en API format bien formado.

    - dict no vacio
    - cada nodo tiene `class_type` (str) e `inputs` (dict)
    - toda conexion `[node_id, output_index]` apunta a un nodo existente
    """
    assert isinstance(wf, dict) and wf, "workflow debe ser un dict no vacio"
    ids = set(wf)
    for nid, node in wf.items():
        assert isinstance(node, dict), f"nodo {nid} no es dict"
        assert isinstance(node.get("class_type"), str) and node["class_type"], (
            f"nodo {nid} sin class_type"
        )
        assert isinstance(node.get("inputs"), dict), f"nodo {nid} sin inputs dict"
        for key, val in node["inputs"].items():
            if (
                isinstance(val, list)
                and len(val) == 2
                and isinstance(val[0], str)
                and isinstance(val[1], int)
            ):
                assert val[0] in ids, (
                    f"nodo {nid}.{key} referencia node_id inexistente {val[0]!r}"
                )


def class_types(wf):
    """Conjunto de los `class_type` presentes en el workflow."""
    return {n["class_type"] for n in wf.values()}


def node_by_ct(wf, ct):
    """Primer nodo cuyo `class_type` es `ct` (lanza StopIteration si no hay)."""
    return next(n for n in wf.values() if n["class_type"] == ct)
