"""Tests de comfyui_export_skill_template (función impura, sin ui_graph -> offline).

Verifica el camino headless (sin navegador), que es el que se puede testear sin GPU ni CDP:
- golden: una skill txt2img+facedetailer válida en un library_dir temporal -> ok True, escribe
  exports/<slug>.template.json con API format válido (class_type/inputs) y el subject placeholder
  presente en el prompt,
- edge: respeta export_template_path declarado en la receta,
- error: slug inexistente (sin recipe.json) -> ok False,
- error: receta con base_workflow desconocido -> ok False.

El camino ui_graph=True (carga/extrae el grafo en el navegador vía CDP) se valida en vivo, no
aquí: depende de una pestaña de ComfyUI abierta y queda fuera del alcance de un test offline.
"""

import json
import os
import sys

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

import pytest  # noqa: E402

from ml.comfyui_export_skill_template import export_skill_template  # noqa: E402
from _comfyui_wf_assert import assert_api_format, class_types  # noqa: E402


def _write_skill(library_dir, slug, recipe, *, export_template_path=None):
    skill_dir = os.path.join(library_dir, slug)
    os.makedirs(skill_dir, exist_ok=True)
    if export_template_path is not None:
        recipe = dict(recipe, export_template_path=export_template_path)
    with open(os.path.join(skill_dir, "recipe.json"), "w", encoding="utf-8") as fh:
        json.dump(recipe, fh)
    return skill_dir


def _recipe_txt2img(**over):
    r = {
        "schema_version": 1,
        "slug": "demo_skill",
        "version": "1.0.0",
        "base_workflow": "txt2img",
        "checkpoint": "IMG_dreamshaper_8.safetensors",
        "loras": [],
        "params": {"steps": 28, "cfg": 6.0, "width": 512, "height": 768},
        "prompt_scaffold": {
            "positive": "cinematic portrait of {subject}, sharp focus",
            "negative": "blurry, lowres",
            "trigger_words": [],
        },
        "blocks": [{"type": "facedetailer", "params": {"denoise": 0.4}}],
    }
    r.update(over)
    return r


def test_golden_headless_writes_api_template(tmp_path):
    lib = str(tmp_path / "skills_library")
    _write_skill(lib, "demo_skill", _recipe_txt2img())

    out = export_skill_template("demo_skill", library_dir=lib)  # ui_graph=False por defecto

    assert out["ok"] is True
    assert out["ui_workflow_path"] is None  # sin ui_graph no toca la carpeta nativa
    path = out["template_path"]
    assert os.path.isfile(path)

    workflow = json.load(open(path, encoding="utf-8"))
    assert_api_format(workflow)  # dict {node_id: {class_type, inputs}}
    cts = class_types(workflow)
    assert "CheckpointLoaderSimple" in cts
    assert "FaceDetailer" in cts  # el block facedetailer se aplicó
    # el subject placeholder se mantiene literal en algún CLIPTextEncode
    assert any("{subject}" in json.dumps(node.get("inputs", {})) for node in workflow.values())


def test_edge_respects_export_template_path(tmp_path):
    lib = str(tmp_path / "skills_library")
    _write_skill(lib, "demo_skill", _recipe_txt2img(),
                 export_template_path="exports/custom_name.template.json")

    out = export_skill_template("demo_skill", library_dir=lib)

    assert out["ok"] is True
    assert out["template_path"].endswith(os.path.join("exports", "custom_name.template.json"))
    assert os.path.isfile(out["template_path"])


def test_error_missing_skill(tmp_path):
    lib = str(tmp_path / "skills_library")
    os.makedirs(lib, exist_ok=True)

    out = export_skill_template("no_existe", library_dir=lib)

    assert out["ok"] is False
    assert out["template_path"] is None
    assert "recipe.json" in out["error"]


def test_error_unknown_base_workflow(tmp_path):
    lib = str(tmp_path / "skills_library")
    _write_skill(lib, "bad_skill", _recipe_txt2img(base_workflow="totally_unknown"))

    out = export_skill_template("bad_skill", library_dir=lib)

    assert out["ok"] is False
    assert out["template_path"] is None
    assert "build_skill_workflow" in out["error"]


if __name__ == "__main__":
    sys.exit(pytest.main([__file__, "-v"]))
