"""Tests offline de comfyui_build_decal_overlay_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_decal_overlay_workflow import (  # noqa: E402
    comfyui_build_decal_overlay_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_decal_on_black_recipe():
    wf = comfyui_build_decal_overlay_workflow("blood splatter", on_black=True, seed=7)
    cls = _classes(wf)
    # Cadena base txt2img pura: NO lleva Rembg (el matting es luma-to-alpha aparte).
    assert "CheckpointLoaderSimple" in cls
    assert "KSampler" in cls
    assert "VAEDecode" in cls
    assert "SaveImage" in cls
    assert "Image Rembg (Remove Background)" not in cls
    # El decal + el aislamiento + el fondo negro aparecen en el prompt positivo.
    pos = _pos_with(wf, "blood splatter")
    txt = pos["inputs"]["text"]
    assert "isolated" in txt
    assert "solid pure black background" in txt
    assert "texture overlay" in txt
    assert "game asset" in txt
    # SaveImage toma del VAEDecode directamente (sin recorte intermedio).
    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_on_black_toggles_background():
    # on_black=True -> fondo negro plano (pensado para luma->alpha) + el negativo
    # rechaza fondos de otro color (gris/blanco/texturizado).
    wf_black = comfyui_build_decal_overlay_workflow("rust stain", on_black=True)
    pos_black = _pos_with(wf_black, "rust stain")["inputs"]["text"]
    assert "solid pure black background" in pos_black
    assert "white" not in pos_black
    neg_black = next(
        n["inputs"]["text"] for n in wf_black.values()
        if n["class_type"] == "CLIPTextEncode" and "3d render" in n["inputs"]["text"]
    )
    assert "white background" in neg_black  # rechaza fondo blanco cuando es negro
    # on_black=False -> fondo blanco plano + el negativo rechaza fondo negro.
    wf_white = comfyui_build_decal_overlay_workflow("rust stain", on_black=False)
    pos_white = _pos_with(wf_white, "rust stain")["inputs"]["text"]
    assert "solid pure white background" in pos_white
    assert "black" not in pos_white
    neg_white = next(
        n["inputs"]["text"] for n in wf_white.values()
        if n["class_type"] == "CLIPTextEncode" and "3d render" in n["inputs"]["text"]
    )
    assert "black background" in neg_white  # rechaza fondo negro cuando es blanco


def test_edge_decal_reflected():
    for d in ["wall crack", "mud splatter", "burn mark"]:
        wf = comfyui_build_decal_overlay_workflow(d)
        pos = _pos_with(wf, d)
        assert d in pos["inputs"]["text"]


def test_edge_style_in_prompt():
    wf = comfyui_build_decal_overlay_workflow(
        "blood splatter", style="stylized blood, painterly"
    )
    pos = _pos_with(wf, "blood splatter")
    assert "stylized blood, painterly" in pos["inputs"]["text"]


def test_edge_size_reflected():
    wf = comfyui_build_decal_overlay_workflow("dirt grunge", size=768)
    latent = _by_class(wf, "EmptyLatentImage")[0]["inputs"]
    assert latent["width"] == 768
    assert latent["height"] == 768  # cuadrado


def test_edge_negative_isolates_decal():
    # El negativo por defecto rechaza objetos/escena/profundidad/marco que delaten
    # una composicion (queremos una textura plana aislada).
    wf = comfyui_build_decal_overlay_workflow("scratch marks")
    neg = next(
        n["inputs"]["text"]
        for n in wf.values()
        if n["class_type"] == "CLIPTextEncode" and "3d render" in n["inputs"]["text"]
    )
    assert "3d render" in neg
    assert "scene" in neg
    assert "vignette" in neg
    assert "frame" in neg
    assert "textured background" in neg  # fondo plano forzado


def test_edge_lora_reflected():
    wf = comfyui_build_decal_overlay_workflow(
        "rust stain", lora="SD15_grunge.safetensors", lora_strength=0.8
    )
    loras = _by_class(wf, "LoraLoader")
    assert len(loras) == 1
    assert loras[0]["inputs"]["lora_name"] == "SD15_grunge.safetensors"
    assert loras[0]["inputs"]["strength_model"] == 0.8


def test_error_empty_decal():
    try:
        comfyui_build_decal_overlay_workflow("  ")
        assert False
    except ValueError as e:
        assert "decal" in str(e)


def test_determinism():
    a = comfyui_build_decal_overlay_workflow(
        "blood splatter", on_black=True, lora="SD15_grunge.safetensors", seed=7
    )
    b = comfyui_build_decal_overlay_workflow(
        "blood splatter", on_black=True, lora="SD15_grunge.safetensors", seed=7
    )
    assert a == b
