"""Tests offline de comfyui_build_prop_object_workflow (estructura del dict, sin GPU)."""

import os
import sys

sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from ml.comfyui_build_prop_object_workflow import (  # noqa: E402
    comfyui_build_prop_object_workflow,
)


def _classes(wf):
    return sorted({n["class_type"] for n in wf.values()})


def _by_class(wf, cls):
    return [n for n in wf.values() if n["class_type"] == cls]


def _id_of(wf, cls):
    return next(nid for nid, n in wf.items() if n["class_type"] == cls)


def _pos_with(wf, needle):
    return next(
        n for n in wf.values()
        if n["class_type"] == "CLIPTextEncode" and needle in n["inputs"]["text"]
    )


def test_golden_transparent_recipe():
    wf = comfyui_build_prop_object_workflow(
        "wooden treasure chest", transparent=True, seed=7
    )
    cls = _classes(wf)
    # Cadena base txt2img + Rembg para alpha.
    assert "CheckpointLoaderSimple" in cls
    assert "KSampler" in cls
    assert "VAEDecode" in cls
    assert "SaveImage" in cls
    assert "Image Rembg (Remove Background)" in cls
    # El prop aparece en el prompt positivo con el scaffold de objeto de mundo.
    pos = _pos_with(wf, "wooden treasure chest")
    txt = pos["inputs"]["text"]
    assert "single object" in txt
    assert "centered" in txt
    assert "game asset" in txt
    assert "plain background" in txt
    # SaveImage toma la imagen del Rembg (no del VAEDecode).
    rembg_id = _id_of(wf, "Image Rembg (Remove Background)")
    save = next(n for n in wf.values() if n["class_type"] == "SaveImage")
    assert save["inputs"]["images"] == [rembg_id, 0]
    assert _by_class(wf, "Image Rembg (Remove Background)")[0]["inputs"]["transparency"] is True


def test_edge_opaque_no_rembg():
    wf = comfyui_build_prop_object_workflow("stone fountain", transparent=False)
    assert "Image Rembg (Remove Background)" not in _classes(wf)
    # SaveImage toma del VAEDecode directamente.
    vd_id = _id_of(wf, "VAEDecode")
    save = next(n for n in wf.values() if n["class_type"] == "SaveImage")
    assert save["inputs"]["images"] == [vd_id, 0]


def test_edge_size_reflected():
    wf = comfyui_build_prop_object_workflow("mossy rock", size=768)
    latent = _by_class(wf, "EmptyLatentImage")[0]["inputs"]
    assert latent["width"] == 768
    assert latent["height"] == 768  # cuadrado


def test_edge_prop_at_start():
    # El scaffold arranca directamente con el prop.
    wf = comfyui_build_prop_object_workflow("potted plant", transparent=False)
    pos = _pos_with(wf, "potted plant")
    assert pos["inputs"]["text"].startswith("potted plant")


def test_edge_style_in_prompt():
    # Estilo de MUNDO reflejado (diferenciado del icono plano de inventario).
    wf = comfyui_build_prop_object_workflow(
        "wooden barrel", style="top-down RPG prop", transparent=False
    )
    pos = _pos_with(wf, "wooden barrel")
    assert "top-down RPG prop" in pos["inputs"]["text"]


def test_edge_world_object_not_inventory_icon():
    # Por defecto el scaffold lo trata como objeto de mundo (scene prop), no icono UI.
    wf = comfyui_build_prop_object_workflow("lit torch", transparent=False)
    txt = _pos_with(wf, "lit torch")["inputs"]["text"]
    assert "scene prop" in txt
    assert "world object" in txt
    # El negativo por defecto excluye personas/criaturas (objeto inanimado).
    neg = next(
        n for n in wf.values()
        if n["class_type"] == "CLIPTextEncode" and "person" in n["inputs"]["text"]
    )
    assert "creature" in neg["inputs"]["text"]


def test_edge_lora_reflected():
    wf = comfyui_build_prop_object_workflow(
        "ornate vase",
        lora="SD15_isometric_game_assets.safetensors",
        lora_strength=0.9,
    )
    loras = _by_class(wf, "LoraLoader")
    assert len(loras) == 1
    assert loras[0]["inputs"]["lora_name"] == "SD15_isometric_game_assets.safetensors"
    assert loras[0]["inputs"]["strength_model"] == 0.9


def test_edge_transparent_default_true():
    # transparent por defecto True -> Rembg presente sin pasar el flag.
    wf = comfyui_build_prop_object_workflow("treasure chest")
    assert "Image Rembg (Remove Background)" in _classes(wf)


def test_error_empty_prop():
    try:
        comfyui_build_prop_object_workflow("  ")
        assert False
    except ValueError as e:
        assert "prop" in str(e)


def test_determinism():
    a = comfyui_build_prop_object_workflow(
        "wooden barrel", lora="SDXL_stylized_props.safetensors", seed=7
    )
    b = comfyui_build_prop_object_workflow(
        "wooden barrel", lora="SDXL_stylized_props.safetensors", seed=7
    )
    assert a == b
