"""Construye el workflow ComfyUI de UNA runa / glifo / sigilo magico (API format).

Una runa es un simbolo arcano aislado: glifos runicos, circulos magicos, sigilos
de invocacion, inscripciones brillantes — para hechizos, portales, marcas de
conjuro, efectos de magia. La pieza se genera AISLADA sobre un fondo uniforme
(negro por defecto) para poder extraer luego el canal alpha por luminancia.

La tecnica gamedev correcta para una runa BRILLANTE (glifo que emite luz, circulo
magico incandescente, sigilo neon) es generarla sobre fondo NEGRO y convertir la
luminancia en alpha con `comfyui_matting_luma_to_alpha`: brillante -> opaco,
negro -> transparente. Eso preserva el resplandor (el halo y el degradado del
glow) que un matting binario tipo rembg destruiria. Por eso `glow=True` es el modo
por defecto y el scaffold empuja "glowing on pure black background": el PNG
resultante esta pensado para pasar por luma-to-alpha en un paso aparte y quedar
listo para componer en el motor con un blend mode aditivo. `glow=False` (fondo
plano, sin resplandor) sirve para una runa grabada/mate, recortable luego por el
caller de otra forma.

Es el builder hermano de comfyui_build_status_effect_icon_workflow /
comfyui_build_decal_overlay_workflow: mismo patron (PURO, dict API format) que
compone funciones existentes del registry, no reescribe el grafo. Igual que el
builder de decal, este NO inyecta Rembg: el matting de una runa brillante es
luma-to-alpha (post-proceso de disco), no un nodo del workflow.

DISTINTO de status_effect_icon: un icono de estado es un simbolo SOLIDO de UI con
silueta definida (recorte rembg), pequeño y legible a 16-32 px en el HUD. Una runa
es una marca arcana translucida que emite luz, pensada para inscribirse en el
mundo (suelo, portal, arma) y componerse con blend aditivo — su alpha sale del
resplandor, no de un recorte de silueta.

Cableado:

    CheckpointLoaderSimple -> [LoraLoader opcional de estilo arcano] -> KSampler
                          -> CLIPTextEncode (prompt scaffold de runa aislada) ...
                          -> VAEDecode -> SaveImage  (runa sobre fondo uniforme)

Compone:
  - comfyui_build_txt2img_workflow  -> base txt2img cuadrada
  - comfyui_inject_lora             -> LoRA de estilo arcano opcional (consistencia)

Pipeline despues de generar (no en este builder):
  comfyui_submit_workflow -> comfyui_wait_result -> comfyui_fetch_output_image
  -> comfyui_matting_luma_to_alpha (con glow=True)  -> PNG RGBA listo para el motor

class_types/inputs verificados contra /object_info del servidor (8GB lowvram):
CheckpointLoaderSimple, CLIPTextEncode, EmptyLatentImage, KSampler, VAEDecode,
SaveImage, LoraLoader.

Funcion pura: sin red, sin I/O. Determinista para los mismos argumentos.
"""
from __future__ import annotations

import os
import sys

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

# Negativo comun a cualquier runa: un solo simbolo arcano limpio y centrado, SIN
# escena/objeto 3D/personaje/profundidad ni marco/borde que delaten una
# composicion. Se rechaza tambien el texto legible / caligrafia de alfabetos
# reales para que el modelo dibuje un glifo arcano y no palabras.
_RUNE_NEGATIVE_COMMON = (
    "3d render, object, scene, landscape, character, person, creature, "
    "realistic text, readable words, latin alphabet, sentence, paragraph, "
    "depth of field, perspective, vignette, frame, border, drop shadow, "
    "multiple separate symbols scattered, photo, photorealistic, "
    "blurry, low quality, jpeg artifacts, watermark, signature, logo"
)

# Refuerzo de fondo segun glow: con glow=True el fondo DEBE quedar NEGRO puro y
# plano para que luma->alpha mapee el resplandor a alpha sin recoger basura. Sin
# esto, un style "arcane glowing" arrastra una niebla/textura de fondo que arruina
# el alpha. Con glow=False (runa mate) se rechaza el resplandor para una marca
# grabada plana.
_RUNE_BG_NEG_GLOW = (
    "textured background, gray background, white background, busy background, "
    "background pattern, noisy background, gradient background, fog, smoke clouds"
)
_RUNE_BG_NEG_PLAIN = (
    "glow, glowing, neon, bloom, light rays, lens flare, "
    "busy background, background pattern, noisy background, gradient background"
)


def comfyui_build_rune_glyph_workflow(
    glyph: str,
    *,
    glow: bool = True,
    style: str = "arcane glowing rune",
    checkpoint: str = "IMG_dreamshaper_8.safetensors",
    size: int = 512,
    seed: int = 0,
    lora: str | None = None,
    lora_strength: float = 1.0,
    negative: str | None = None,
    steps: int = 28,
    cfg: float = 7.0,
    sampler_name: str = "dpmpp_2m",
    scheduler: str = "karras",
    filename_prefix: str = "rune_glyph",
) -> dict:
    """Construye el dict (API format) del workflow de UNA runa / glifo / sigilo.

    Args:
        glyph: descripcion del simbolo arcano a generar (ej. "circular summoning
            rune", "ancient norse rune", "magic circle with glyphs", "demonic
            sigil", "elven inscription", "protective ward symbol", "fire spell
            glyph"). Se inserta en un prompt scaffold de runa aislada. No puede
            estar vacio.
        glow: si True (defecto) la runa se genera BRILLANTE sobre fondo NEGRO puro,
            pensada para extraer el alpha por luminancia con
            comfyui_matting_luma_to_alpha (conserva el resplandor para componer con
            blend aditivo en el motor). Si False se genera una runa MATE/grabada
            sobre fondo plano, sin resplandor (recorte/inversion por el caller).
            keyword-only.
        style: descriptor de estilo arcano que mantiene consistentes las runas de
            un set (ej. "arcane glowing rune", "fiery demonic sigil", "icy blue
            magic circle", "golden holy glyph", "engraved stone rune"). Pasa el
            MISMO style + checkpoint + (lora) a todas las runas de un grimorio para
            coherencia visual. keyword-only.
        checkpoint: checkpoint del servidor. 'IMG_dreamshaper_8.safetensors' (SD1.5,
            holgado en 8GB lowvram) por defecto; 'IMG_juggernaut_xl_v11.safetensors'
            para SDXL (mas VRAM, subir size a 768/1024). keyword-only.
        size: lado del cuadrado en px (width = height = size). 512 SD1.5 por
            defecto. keyword-only.
        seed: semilla del KSampler. Misma seed + mismos glyph/style -> mismo
            simbolo; variar seed da variantes del mismo tipo de runa. keyword-only.
        lora: LoRA de estilo arcano opcional en models/loras. None = sin LoRA.
            keyword-only.
        lora_strength: fuerza del LoRA sobre model y clip. Se clampa a [0.0, 2.0].
            keyword-only.
        negative: prompt negativo. None usa el negativo por defecto pensado para
            una runa aislada (un simbolo arcano centrado, sin escena/objeto/texto
            legible/marco, fondo plano). keyword-only.
        steps, cfg, sampler_name, scheduler, filename_prefix: parametros de
            generacion. keyword-only.

    Returns:
        dict en API format listo para comfyui_submit_workflow: txt2img base
        cuadrada con prompt scaffold de runa ('{glyph}, {style}, magic symbol,
        isolated, glowing on pure black background | plain background, centered,
        game asset, ...') + LoRA de estilo opcional. NO lleva Rembg: con glow=True
        el PNG resultante se convierte a RGBA con comfyui_matting_luma_to_alpha
        (luma=alpha) en un paso posterior. Es UNA runa; un grimorio completo ->
        llamar por glyph con el mismo style/checkpoint/lora.

    Raises:
        ValueError: si glyph esta vacio.
    """
    from ml.comfyui_build_txt2img_workflow import comfyui_build_txt2img_workflow

    if not glyph or not glyph.strip():
        raise ValueError(
            "comfyui_build_rune_glyph_workflow: 'glyph' no puede estar vacio"
        )

    glyph = glyph.strip()
    lora_strength = max(0.0, min(2.0, float(lora_strength)))
    if negative is None:
        bg_neg = _RUNE_BG_NEG_GLOW if glow else _RUNE_BG_NEG_PLAIN
        neg = f"{_RUNE_NEGATIVE_COMMON}, {bg_neg}"
    else:
        neg = negative

    # Prompt scaffold de runa aislada: un simbolo arcano plano, centrado, sobre
    # fondo UNIFORME. Con glow=True el fondo es NEGRO puro y la runa resplandece
    # (-> luma-to-alpha despues, blend aditivo en el motor); con glow=False es una
    # marca mate sobre fondo plano. El fondo se refuerza para que el resplandor no
    # se derrame en una niebla que arruine el alpha.
    bg = (
        "glowing on a solid pure black background, flat black backdrop, "
        "emissive light, bright lines on black"
        if glow
        else "on a plain flat background, matte engraved symbol"
    )
    positive = (
        f"{glyph}, {style}, magic symbol, single isolated glyph, centered, {bg}, "
        "occult sigil, arcane inscription, no scenery, game asset, "
        "high detail, crisp lines"
    )

    wf = comfyui_build_txt2img_workflow(
        checkpoint,
        positive,
        neg,
        steps=steps,
        cfg=cfg,
        width=size,
        height=size,
        seed=seed,
        sampler_name=sampler_name,
        scheduler=scheduler,
        filename_prefix=filename_prefix,
    )

    if lora:
        from ml.comfyui_inject_lora import comfyui_inject_lora

        wf = comfyui_inject_lora(
            wf, lora, strength_model=lora_strength, strength_clip=lora_strength
        )

    return wf


if __name__ == "__main__":
    import json

    wf = comfyui_build_rune_glyph_workflow(
        "circular summoning rune",
        glow=True,
        style="arcane glowing rune",
        seed=11,
    )
    print(
        json.dumps(
            {
                "nodes": list(wf),
                "classes": sorted({n["class_type"] for n in wf.values()}),
            },
            indent=2,
        )
    )
