"""Construye el workflow ComfyUI de UN vehiculo/montura de juego (API format).

Vehiculo o montura de juego (caballo, dragon-montura, nave espacial, coche, barco,
carro, grifo, moto, carruaje...): el vehiculo COMPLETO en vista lateral o isometrica,
centrado, fondo limpio y uniforme recortable a alpha, SIN jinete/conductor, para que
el motor coloque encima al personaje que lo usa o lo conduce. Es el builder hermano
de comfyui_build_enemy_creature_workflow / comfyui_build_prop_object_workflow: mismo
patron (PURO, dict API format) que compone funciones existentes del registry, no
reescribe el grafo.

Diferencia con enemy_creature y prop_object (clave para no duplicar): una *criatura*
es un sujeto vivo en pose de combate (sprite/token hostil); un *prop* es atrezzo
inanimado que decora el nivel y no se interactua. Un *vehiculo/montura* es un objeto
que el personaje USA o MONTA: se genera vacio (sin jinete) y a escala de vehiculo
para que el personaje quepa encima/dentro. Por eso el scaffold empuja "full vehicle,
no rider, no driver, empty" y el negativo rechaza "person, rider, driver,
passenger". Una montura viva (caballo, dragon) que el personaje cabalga entra aqui,
no en enemy_creature, porque el objetivo es montarla, no combatirla.

Cableado:

    CheckpointLoaderSimple -> [LoraLoader opcional de estilo] -> KSampler
                          -> CLIPTextEncode (prompt scaffold de vehiculo) ...
                          -> VAEDecode -> [Image Rembg opcional] -> SaveImage

Compone:
  - comfyui_build_txt2img_workflow  -> base txt2img cuadrada
  - comfyui_inject_lora             -> LoRA de estilo opcional (consistencia del set)
  - 'Image Rembg (Remove Background)' (helper local) -> fondo transparente (alpha)

Por que Rembg y NO comfyui_matting_luma_to_alpha: un vehiculo es un sujeto SOLIDO
con silueta definida (coche, barco, caballo); rembg recorta limpio la silueta
dejando alpha, listo para soltar en la escena con el personaje encima. La
luma-to-alpha es para translucidos sobre negro (humo/fuego/magia), donde aplanaria
el vehiculo. Si el vehiculo es etereo o translucido (nave de energia, montura
espectral) y se quiere conservar la translucidez, recortar fuera del workflow
(transparent=False) y componer con luma-to-alpha en un paso aparte. Para el parque
movil tipico (caballo, coche, nave, barco) rembg es lo correcto.

Por que `view` (side/iso) y no meterlo en `style`: la vista define la geometria del
vehiculo y debe ser explicita y consistente con el resto de assets del juego — un
side-scroller pide "side view", un RPG isometrico pide "isometric view". Separar
`view` deja fijar la perspectiva del parque movil entero variando solo `vehicle`.

class_types/inputs verificados contra /object_info del servidor (8GB lowvram):
CheckpointLoaderSimple, CLIPTextEncode, EmptyLatentImage, KSampler, VAEDecode,
SaveImage, LoraLoader, 'Image Rembg (Remove Background)' (transparency BOOLEAN).

Funcion pura: sin red, sin I/O. No muta dicts de entrada (copia profunda en el
helper de rembg). Determinista para los mismos argumentos.
"""
from __future__ import annotations

import copy
import os
import sys

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

# Negativo por defecto pensado para vehiculos/monturas: UN vehiculo entero, bien
# formado, VACIO (sin jinete/conductor), fondo limpio, sin texto/marcas ni recortes.
# No filtra ningun tipo de vehiculo (terrestre, aereo, naval, montura viva, mecanico).
_VEHICLE_NEGATIVE = (
    "person, people, rider, driver, passenger, pilot, character, crowd, "
    "multiple vehicles, blurry, lowres, deformed, disfigured, bad anatomy, "
    "mutated, ugly, text, watermark, signature, logo, photo, photorealistic, "
    "cropped, cut off, out of frame, jpeg artifacts"
)


def _inject_rembg(workflow: dict, model: str) -> dict:
    """Inserta 'Image Rembg (Remove Background)' (transparency=True) entre VAEDecode y SaveImage.

    Mismo helper que usan comfyui_build_enemy_creature_workflow / prop_object: el nodo
    recorta la silueta del vehiculo dejando alpha. Repunta SaveImage.images a la salida
    del Rembg.
    """
    wf = copy.deepcopy(workflow)
    vaedecode_id = next(
        (nid for nid, n in wf.items() if n.get("class_type") == "VAEDecode"), None
    )
    save_id = next((nid for nid, n in wf.items() if n.get("class_type") == "SaveImage"), None)
    if vaedecode_id is None or save_id is None:
        raise ValueError(
            "comfyui_build_vehicle_mount_workflow: no se encontro VAEDecode/SaveImage para Rembg"
        )
    numeric = [int(k) for k in wf.keys() if str(k).isdigit()]
    rembg_id = str((max(numeric) + 1) if numeric else len(wf) + 1)
    wf[rembg_id] = {
        "class_type": "Image Rembg (Remove Background)",
        "inputs": {
            "images": [vaedecode_id, 0],
            "transparency": True,
            "model": model,
            "post_processing": False,
            "only_mask": False,
            "alpha_matting": False,
            "alpha_matting_foreground_threshold": 240,
            "alpha_matting_background_threshold": 10,
            "alpha_matting_erode_size": 10,
            "background_color": "none",
        },
    }
    wf[save_id]["inputs"]["images"] = [rembg_id, 0]
    return wf


def comfyui_build_vehicle_mount_workflow(
    vehicle: str,
    *,
    view: str = "side",
    style: str = "game vehicle",
    checkpoint: str = "IMG_dreamshaper_8.safetensors",
    size: int = 512,
    transparent: bool = True,
    seed: int = 0,
    lora: str | None = None,
    lora_strength: float = 1.0,
    rembg_model: str = "u2net",
    negative: str | None = None,
    steps: int = 28,
    cfg: float = 7.0,
    sampler_name: str = "dpmpp_2m",
    scheduler: str = "karras",
    filename_prefix: str = "vehicle_mount",
) -> dict:
    """Construye el dict (API format) del workflow de un vehiculo/montura de juego.

    Args:
        vehicle: descripcion del vehiculo o montura (ej. "armored war horse with
            saddle", "fantasy dragon mount", "small spaceship", "red sports car",
            "wooden sailing ship", "war chariot", "griffon mount"). Se inserta en un
            prompt scaffold de vehiculo. No puede estar vacio.
        view: vista/perspectiva del vehiculo. "side" (lateral, para side-scrollers y
            presentacion limpia) por defecto; "iso"/"isometric" para RPG isometrico;
            tambien vale texto libre ("three-quarter", "top-down"). Se inserta como
            "{view} view" en el prompt para fijar la geometria del parque movil.
            keyword-only.
        style: descriptor de estilo que mantiene consistentes los vehiculos del set
            (ej. "game vehicle", "stylized fantasy mount", "sci-fi spaceship art",
            "cartoon racing car", "pixel art vehicle"). Pasa el MISMO style +
            checkpoint + (lora) + view a todos los vehiculos para coherencia visual.
            keyword-only.
        checkpoint: checkpoint del servidor. 'IMG_dreamshaper_8.safetensors' (SD1.5,
            holgado en 8GB lowvram) por defecto; 'IMG_juggernaut_xl_v11.safetensors'
            para SDXL (mas VRAM, subir size a 768/1024). keyword-only.
        size: lado del cuadrado en px (width = height = size). 512 SD1.5 por
            defecto. keyword-only.
        transparent: si True inyecta Image Rembg y el PNG sale con alpha (fondo
            recortado, listo para soltar en la escena con el personaje encima). Si
            False deja el vehiculo opaco sobre fondo plano, recortable luego por el
            caller/pipeline. keyword-only.
        seed: semilla del KSampler. Misma seed + mismo vehicle/view/style -> mismo
            vehiculo. keyword-only.
        lora: LoRA de estilo opcional en models/loras (ej.
            'SD15_vehicle_concept.safetensors', 'SDXL_mecha.safetensors'). None = sin
            LoRA. keyword-only.
        lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0].
            keyword-only.
        rembg_model: modelo Rembg ('u2net' general, 'isnet-anime' para anime). Solo
            se usa si transparent=True. keyword-only.
        negative: prompt negativo. None usa el negativo por defecto pensado para
            vehiculos (un vehiculo entero VACIO sin jinete/conductor, fondo limpio,
            sin texto/recorte). keyword-only.
        steps, cfg, sampler_name, scheduler, filename_prefix: parametros de
            generacion. keyword-only.

    Returns:
        dict en API format listo para comfyui_submit_workflow: txt2img base cuadrada
        con prompt scaffold de vehiculo ('{vehicle}, {view} view, {style}, full
        vehicle, centered, plain background, game asset, no rider, ...') + LoRA de
        estilo opcional + Image Rembg (si transparent). Es UN vehiculo; para un parque
        movil -> llamar por cada vehicle con el mismo view/style/checkpoint/(lora).
        Montar el set con comfyui_build_grid si se quiere un contact-sheet.

    Raises:
        ValueError: si vehicle esta vacio, o si la base no tiene VAEDecode/SaveImage
            donde inyectar el Rembg (propagado por el helper).
    """
    from ml.comfyui_build_txt2img_workflow import comfyui_build_txt2img_workflow

    if not vehicle or not vehicle.strip():
        raise ValueError(
            "comfyui_build_vehicle_mount_workflow: 'vehicle' no puede estar vacio"
        )

    vehicle = vehicle.strip()
    view = (view or "side").strip()
    lora_strength = max(0.0, min(2.0, float(lora_strength)))
    neg = _VEHICLE_NEGATIVE if negative is None else negative

    # Prompt scaffold de vehiculo: el vehiculo entero en su vista, centrado, fondo
    # plano, VACIO (sin jinete), listo como asset de juego recortable que el personaje
    # usara/conducira encima.
    positive = (
        f"{vehicle}, {view} view, {style}, full vehicle, centered, plain background, "
        "game asset, single vehicle, no rider, empty, high detail"
    )

    wf = comfyui_build_txt2img_workflow(
        checkpoint,
        positive,
        neg,
        steps=steps,
        cfg=cfg,
        width=size,
        height=size,
        seed=seed,
        sampler_name=sampler_name,
        scheduler=scheduler,
        filename_prefix=filename_prefix,
    )

    if lora:
        from ml.comfyui_inject_lora import comfyui_inject_lora

        wf = comfyui_inject_lora(
            wf, lora, strength_model=lora_strength, strength_clip=lora_strength
        )

    if transparent:
        wf = _inject_rembg(wf, rembg_model)

    return wf


if __name__ == "__main__":
    import json

    wf = comfyui_build_vehicle_mount_workflow(
        "armored war horse with saddle",
        view="side",
        style="stylized fantasy mount",
        transparent=True,
        seed=7,
    )
    print(
        json.dumps(
            {
                "nodes": list(wf),
                "classes": sorted({n["class_type"] for n in wf.values()}),
            },
            indent=2,
        )
    )
