"""Encadena N nodos LoraLoader en un workflow ComfyUI ya construido (API format).

Reusa comfyui_inject_lora una vez por LoRA: la salida MODEL/CLIP de cada
LoraLoader alimenta al siguiente, formando una cadena
checkpoint -> lora[0] -> lora[1] -> ... -> lora[n-1] -> KSampler/CLIPTextEncode.

El primer elemento de `loras` queda mas cerca del checkpoint y el ultimo mas
cerca de los consumidores (KSampler.model, CLIPTextEncode.clip). El orden se
respeta: apilar [estilo, detalle] no es lo mismo que [detalle, estilo].

Funcion pura: no muta el dict de entrada (comfyui_inject_lora trabaja sobre
copias profundas, asi que la cadena tampoco toca el workflow original).
"""
from __future__ import annotations

import os
import sys

sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))


def comfyui_inject_multi_lora(workflow: dict, loras: list[dict]) -> dict:
    """Devuelve una copia del workflow con N LoraLoader encadenados.

    Args:
        workflow: dict en API format (ej. salida de
            comfyui_build_txt2img_workflow). No se muta.
        loras: lista de dicts, uno por LoRA, aplicados en orden. Cada dict:
            - name (str, obligatorio): archivo .safetensors en models/loras/.
            - strength_model (float, opcional, default 1.0): fuerza sobre el UNet.
            - strength_clip (float, opcional, default 1.0): fuerza sobre el CLIP.
            Una lista vacia devuelve una copia del workflow sin cambios.

    Returns:
        copia del workflow con los LoraLoader insertados y reconectados. Cada
        LoRA recibe el node_id `max(ids numericos) + 1` en el momento de
        insertarse, asi que los ids crecen en el orden de la lista.

    Raises:
        ValueError: si algun elemento de `loras` no es un dict, le falta 'name',
            o el name esta vacio. Tambien propaga el ValueError de
            comfyui_inject_lora si no puede determinar la fuente model/clip.
    """
    from ml.comfyui_inject_lora import comfyui_inject_lora

    if not isinstance(loras, list):
        raise ValueError(
            f"comfyui_inject_multi_lora: 'loras' debe ser una lista, no {type(loras).__name__}"
        )

    wf = workflow
    for i, lora in enumerate(loras):
        if not isinstance(lora, dict):
            raise ValueError(
                f"comfyui_inject_multi_lora: loras[{i}] debe ser un dict "
                f"{{name, strength_model, strength_clip}}, no {type(lora).__name__}"
            )
        name = lora.get("name")
        if not name:
            raise ValueError(
                f"comfyui_inject_multi_lora: loras[{i}] necesita la clave 'name' "
                "con el archivo del LoRA"
            )
        wf = comfyui_inject_lora(
            wf,
            name,
            strength_model=float(lora.get("strength_model", 1.0)),
            strength_clip=float(lora.get("strength_clip", 1.0)),
        )
    return wf


if __name__ == "__main__":
    import json

    from ml.comfyui_build_txt2img_workflow import comfyui_build_txt2img_workflow

    base = comfyui_build_txt2img_workflow("IMG_dreamshaper_8.safetensors", "a robot, 3d render")
    wf = comfyui_inject_multi_lora(
        base,
        [
            {"name": "SD15_3d_render_redmond.safetensors", "strength_model": 0.9},
            {"name": "SD15_detail_tweaker.safetensors", "strength_model": 0.5, "strength_clip": 0.5},
        ],
    )
    print(json.dumps(wf, indent=2))
