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

import os
import sys

import pytest

sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from ml.comfyui_build_splash_art_workflow import (  # noqa: E402
    comfyui_build_splash_art_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 _positive(wf, needle):
    return next(
        n
        for n in wf.values()
        if n["class_type"] == "CLIPTextEncode" and needle in n["inputs"]["text"]
    )


def test_golden_hires_recipe():
    wf = comfyui_build_splash_art_workflow(
        "a lone hero before a dark castle, storm",
        mood="epic, cinematic",
        checkpoint="IMG_dreamshaper_8.safetensors",
        hires=True,
        seed=7,
    )
    cls = _classes(wf)
    # Cadena base + 2a pasada de detalle (hires).
    assert "CheckpointLoaderSimple" in cls
    assert "KSampler" in cls
    assert "VAEDecode" in cls
    assert "UltimateSDUpscale" in cls
    assert "UpscaleModelLoader" in cls
    assert "SaveImage" in cls
    # La scene aparece en el prompt positivo con el scaffold de key art.
    pos = _positive(wf, "a lone hero before a dark castle, storm")
    assert "epic, cinematic" in pos["inputs"]["text"]
    assert "key art" in pos["inputs"]["text"]
    assert "cinematic composition" in pos["inputs"]["text"]
    assert "wide shot" in pos["inputs"]["text"]
    assert "dramatic lighting" in pos["inputs"]["text"]
    # Formato apaisado de pantalla: la base es width > height (16:9).
    latent = _by_class(wf, "EmptyLatentImage")[0]["inputs"]
    assert latent["width"] == 1024
    assert latent["height"] == 576
    assert latent["width"] > latent["height"]
    # Regresion: UltimateSDUpscale exige batch_size (input requerido segun
    # /object_info). Sin el, el submit con hires=True fallaba con node_errors.
    usd = _by_class(wf, "UltimateSDUpscale")[0]["inputs"]
    assert usd["batch_size"] == 1


def test_edge_no_hires_plain_txt2img():
    wf = comfyui_build_splash_art_workflow(
        "a spaceship fleet approaching a ringed planet",
        checkpoint="IMG_dreamshaper_8.safetensors",
        hires=False,
    )
    cls = _classes(wf)
    assert "UltimateSDUpscale" not in cls
    assert "UpscaleModelLoader" not in cls
    # SaveImage toma del VAEDecode directamente.
    vd_id = next(nid for nid, n in wf.items() if n["class_type"] == "VAEDecode")
    save = next(n for n in wf.values() if n["class_type"] == "SaveImage")
    assert save["inputs"]["images"] == [vd_id, 0]


def test_edge_dims_reflected_landscape():
    wf = comfyui_build_splash_art_workflow(
        "an ancient forest temple", width=1152, height=640, hires=False
    )
    latent = _by_class(wf, "EmptyLatentImage")[0]["inputs"]
    assert latent["width"] == 1152
    assert latent["height"] == 640
    assert latent["width"] > latent["height"]  # sigue siendo apaisado 16:9


def test_edge_mood_in_prompt():
    wf = comfyui_build_splash_art_workflow(
        "a derelict station drifting in space", mood="dark, ominous", hires=False
    )
    pos = _positive(wf, "a derelict station drifting in space")
    assert "dark, ominous" in pos["inputs"]["text"]


def test_edge_lora_reflected():
    wf = comfyui_build_splash_art_workflow(
        "a knight raising a banner on a hill",
        lora="SD15_concept_art.safetensors",
        lora_strength=0.9,
        hires=False,
    )
    loras = _by_class(wf, "LoraLoader")
    assert len(loras) == 1
    assert loras[0]["inputs"]["lora_name"] == "SD15_concept_art.safetensors"
    assert loras[0]["inputs"]["strength_model"] == 0.9
    # Con lora el KSampler.model ya NO viene del checkpoint directo.
    ksampler = _by_class(wf, "KSampler")[0]
    lora_id = next(nid for nid, n in wf.items() if n["class_type"] == "LoraLoader")
    assert ksampler["inputs"]["model"] == [lora_id, 0]


def test_edge_lora_strength_clamped():
    wf = comfyui_build_splash_art_workflow(
        "a volcano erupting at night", lora="x.safetensors", lora_strength=5.0, hires=False
    )
    loras = _by_class(wf, "LoraLoader")
    assert loras[0]["inputs"]["strength_model"] == 2.0  # clamp a [0.0, 2.0]


def test_edge_hires_reflected_in_upscale():
    # hires=True debe encadenar UltimateSDUpscale con el upscale_by dado.
    wf = comfyui_build_splash_art_workflow(
        "a dragon over a burning city", hires=True, upscale_by=2.0, seed=3
    )
    usd = _by_class(wf, "UltimateSDUpscale")[0]["inputs"]
    assert usd["upscale_by"] == 2.0


def test_error_empty_scene():
    with pytest.raises(ValueError):
        comfyui_build_splash_art_workflow("   ", hires=False)


def test_determinism():
    a = comfyui_build_splash_art_workflow("a castle siege at dawn", hires=False, seed=3)
    b = comfyui_build_splash_art_workflow("a castle siege at dawn", hires=False, seed=3)
    assert a == b
