"""Tests de comfyui_build_facedetailer_workflow (builder puro, sin red)."""

import os
import sys

import pytest

sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))

from ml.comfyui_build_facedetailer_workflow import comfyui_build_facedetailer_workflow  # noqa: E402
from ml.comfyui_build_txt2img_workflow import comfyui_build_txt2img_workflow  # noqa: E402


def test_image_mode_builds_detailer_chain():
    wf = comfyui_build_facedetailer_workflow(
        "portrait_00001_.png",
        ckpt_name="IMG_dreamshaper_8.safetensors",
        positive="detailed face",
        seed=42,
    )
    # Detector + FaceDetailer + SaveImage presentes.
    assert wf["fd_det"]["class_type"] == "UltralyticsDetectorProvider"
    assert wf["fd_face"]["class_type"] == "FaceDetailer"
    assert wf["fd_save"]["class_type"] == "SaveImage"
    # La imagen viene del LoadImage propio del modo str.
    assert wf["fd_load"]["class_type"] == "LoadImage"
    assert wf["fd_face"]["inputs"]["image"] == ["fd_load", 0]
    # FaceDetailer conecta el bbox_detector y la conditioning.
    assert wf["fd_face"]["inputs"]["bbox_detector"] == ["fd_det", 0]
    assert wf["fd_face"]["inputs"]["positive"] == ["fd_pos", 0]
    assert wf["fd_face"]["inputs"]["seed"] == 42


def test_workflow_mode_reuses_base_nodes():
    base = comfyui_build_txt2img_workflow(
        ckpt_name="IMG_dreamshaper_8.safetensors",
        positive="portrait of a woman",
        seed=7,
    )
    wf = comfyui_build_facedetailer_workflow(
        base,
        ckpt_name="IMG_dreamshaper_8.safetensors",
        positive="detailed face",
        denoise=0.45,
    )
    # Los nodos del base se conservan.
    assert wf["4"]["class_type"] == "CheckpointLoaderSimple"
    assert wf["8"]["class_type"] == "VAEDecode"
    # La imagen del detailer viene del VAEDecode del base.
    assert wf["fd_face"]["inputs"]["image"] == ["8", 0]
    # Reutiliza el checkpoint del base (model/clip/vae del nodo "4").
    assert wf["fd_face"]["inputs"]["model"] == ["4", 0]
    assert wf["fd_face"]["inputs"]["vae"] == ["4", 2]
    assert wf["fd_face"]["inputs"]["denoise"] == 0.45


def test_normalizes_short_bbox_model():
    wf = comfyui_build_facedetailer_workflow(
        "x.png", ckpt_name="IMG_dreamshaper_8.safetensors", positive="face",
        bbox_model="face_yolov8m.pt",
    )
    assert wf["fd_det"]["inputs"]["model_name"] == "bbox/face_yolov8m.pt"
    # Un nombre ya prefijado se respeta.
    wf2 = comfyui_build_facedetailer_workflow(
        "x.png", ckpt_name="IMG_dreamshaper_8.safetensors", positive="face",
        bbox_model="bbox/face_yolov8m.pt",
    )
    assert wf2["fd_det"]["inputs"]["model_name"] == "bbox/face_yolov8m.pt"


def test_dict_without_vaedecode_raises():
    with pytest.raises(ValueError):
        comfyui_build_facedetailer_workflow(
            {"1": {"class_type": "LoadImage", "inputs": {"image": "x.png"}}},
            ckpt_name="IMG_dreamshaper_8.safetensors",
            positive="face",
        )


def test_invalid_base_type_raises():
    with pytest.raises(ValueError):
        comfyui_build_facedetailer_workflow(
            123, ckpt_name="IMG_dreamshaper_8.safetensors", positive="face",
        )


def test_determinista():
    # Builder puro: misma entrada -> mismo dict (sin red, seed fijo, sin estado).
    kw = dict(ckpt_name="IMG_dreamshaper_8.safetensors", positive="detailed face", seed=42)
    a = comfyui_build_facedetailer_workflow("portrait_00001_.png", **kw)
    b = comfyui_build_facedetailer_workflow("portrait_00001_.png", **kw)
    assert a == b
