"""Construye un workflow ComfyUI imagen->malla 3D texturizada multi-vista (API format).

Usa el wrapper ComfyUI-Hunyuan3DWrapper (kijai): genera la geometria con
Hy3DGenerateMesh/Hy3DVAEDecode, la limpia y le hace UV unwrap, renderiza N vistas
de camara, sintetiza la textura multi-vista (Hy3DSampleMultiView) opcionalmente
mejorada con un upscaler ESRGAN (Remacri), la hornea sobre el atlas UV
(Hy3DBakeFromMultiview), rellena los huecos por vertices y exporta el GLB con
material PBR. Portado del pipeline validado en el report 0082 (cobertura de atlas
32.93 % con 6 vistas + Remacri + octree 384).

Funcion pura: sin red, sin I/O. Determinista para los mismos argumentos.

IMPORTANTE: el grafo es monolitico (shape + paint en un solo dict) por claridad,
pero en 8 GB de VRAM debe ejecutarse en 2 fases (shape -> /free -> paint), no de
una pasada. La separacion en fases y el /free los orquesta el pipeline impuro que
consuma este builder. Ver la seccion Gotchas del .md.
"""

# Vistas de camara soportadas: tabla (azimuths, elevations, weights) por numero de vistas.
# 4 = front/left/back/right; 6 anade top/bottom (rellena concavidades que 4 camaras no ven).
_CAMERA_PRESETS = {
    4: {
        "camera_azimuths": "0, 90, 180, 270",
        "camera_elevations": "0, 0, 0, 0",
        "view_weights": "1, 0.1, 0.5, 0.1",
    },
    6: {
        "camera_azimuths": "0, 90, 180, 270, 0, 180",
        "camera_elevations": "0, 0, 0, 0, 90, -90",
        "view_weights": "1, 0.1, 0.5, 0.1, 0.05, 0.05",
    },
}


def comfyui_build_textured_3d_multiview_workflow(
    image_name: str,
    *,
    ckpt: str = "3D_hunyuan3d-dit-v2-mv.safetensors",
    views: int = 6,
    octree: int = 384,
    max_faces: int = 50000,
    upscale_model: str = "4x_foolhardy_Remacri.pth",
) -> dict:
    """Construye el dict del workflow imagen->3D texturizado multi-vista.

    Args:
        image_name: nombre del archivo de imagen de referencia tal como lo ve el
            servidor ComfyUI en su carpeta input/ (subido con POST /upload/image).
        ckpt: checkpoint del modelo de forma Hunyuan3D para Hy3DModelLoader (por
            defecto el variante multi-vista 3D_hunyuan3d-dit-v2-mv). keyword-only.
        views: numero de vistas de camara: 4 (front/left/back/right) o 6 (anade
            top/bottom). Cualquier otro valor lanza ValueError. keyword-only.
        octree: octree_resolution del Hy3DVAEDecode (mas alto = malla mas fina,
            mas VRAM). keyword-only.
        max_faces: max_facenum del Hy3DPostprocessMesh (decimacion de la malla).
            keyword-only.
        upscale_model: nombre del modelo de upscale ESRGAN en upscale_models/ para
            mejorar las vistas antes del bake. Cadena vacia o None desactiva el
            upscale (el bake toma las vistas directas del sample). keyword-only.

    Returns:
        dict en API format listo para comfyui_submit_workflow. node_ids "1".."19"
        (los de upscale "13".."15" solo presentes si upscale_model esta activo).

    Raises:
        ValueError: si views no es 4 ni 6.
    """
    if views not in _CAMERA_PRESETS:
        raise ValueError(
            f"comfyui_build_textured_3d_multiview_workflow: views debe ser 4 o 6, "
            f"no {views!r}"
        )
    cam = _CAMERA_PRESETS[views]

    wf = {
        # --- Fase shape: imagen -> malla limpia con UV ---
        "1": {
            "class_type": "LoadImage",
            "inputs": {"image": image_name},
        },
        "2": {
            "class_type": "Hy3DModelLoader",
            "inputs": {"model": ckpt, "attention_mode": "sdpa", "cublas_ops": False},
        },
        "3": {
            "class_type": "Hy3DGenerateMesh",
            "inputs": {
                "pipeline": ["2", 0],
                "image": ["1", 0],
                "guidance_scale": 5.5,
                "steps": 30,
                "seed": 42,
                "force_offload": True,
            },
        },
        "4": {
            "class_type": "Hy3DVAEDecode",
            "inputs": {
                "vae": ["2", 1],
                "latents": ["3", 0],
                "box_v": 1.01,
                "octree_resolution": octree,
                "num_chunks": 8000,
                "mc_level": 0,
                "mc_algo": "mc",
                "enable_flash_vdm": True,
                "force_offload": True,
            },
        },
        "5": {
            "class_type": "Hy3DPostprocessMesh",
            "inputs": {
                "trimesh": ["4", 0],
                "remove_floaters": True,
                "remove_degenerate_faces": True,
                "reduce_faces": True,
                "max_facenum": max_faces,
                "smooth_normals": False,
            },
        },
        "6": {
            "class_type": "Hy3DMeshUVWrap",
            "inputs": {"trimesh": ["5", 0]},
        },
        # --- Fase paint: render multi-vista + delight + sample + bake + textura ---
        "7": {
            "class_type": "DownloadAndLoadHy3DPaintModel",
            "inputs": {"model": "hunyuan3d-paint-v2-0"},
        },
        "8": {
            "class_type": "DownloadAndLoadHy3DDelightModel",
            "inputs": {"model": "hunyuan3d-delight-v2-0"},
        },
        "9": {
            "class_type": "Hy3DCameraConfig",
            "inputs": {
                "camera_azimuths": cam["camera_azimuths"],
                "camera_elevations": cam["camera_elevations"],
                "view_weights": cam["view_weights"],
                "camera_distance": 1.45,
                "ortho_scale": 1.2,
            },
        },
        "10": {
            "class_type": "Hy3DRenderMultiView",
            "inputs": {
                "trimesh": ["6", 0],
                "render_size": 1024,
                "texture_size": 1024,
                "camera_config": ["9", 0],
                "normal_space": "world",
            },
        },
        "11": {
            "class_type": "Hy3DDelightImage",
            "inputs": {
                "delight_pipe": ["8", 0],
                "image": ["1", 0],
                "steps": 50,
                "width": 512,
                "height": 512,
                "cfg_image": 1.0,
                "seed": 42,
            },
        },
        "12": {
            "class_type": "Hy3DSampleMultiView",
            "inputs": {
                "pipeline": ["7", 0],
                "ref_image": ["11", 0],
                "normal_maps": ["10", 0],
                "position_maps": ["10", 1],
                "view_size": 512,
                "steps": 25,
                "seed": 0,
                "camera_config": ["9", 0],
            },
        },
    }

    # Upscale opcional de los multiviews antes del bake (factor dominante de cobertura).
    if upscale_model:
        wf["13"] = {
            "class_type": "UpscaleModelLoader",
            "inputs": {"model_name": upscale_model},
        }
        wf["14"] = {
            "class_type": "ImageUpscaleWithModel",
            "inputs": {"upscale_model": ["13", 0], "image": ["12", 0]},
        }
        wf["15"] = {
            "class_type": "ImageResize+",
            "inputs": {
                "image": ["14", 0],
                "width": 1024,
                "height": 1024,
                "interpolation": "lanczos",
                "method": "stretch",
                "condition": "always",
                "multiple_of": 0,
            },
        }
        bake_images = ["15", 0]
    else:
        bake_images = ["12", 0]

    wf["16"] = {
        "class_type": "Hy3DBakeFromMultiview",
        "inputs": {
            "images": bake_images,
            "renderer": ["10", 2],
            "camera_config": ["9", 0],
        },
    }
    wf["17"] = {
        "class_type": "Hy3DMeshVerticeInpaintTexture",
        "inputs": {"texture": ["16", 0], "mask": ["16", 1], "renderer": ["16", 2]},
    }
    wf["18"] = {
        "class_type": "Hy3DApplyTexture",
        "inputs": {"texture": ["17", 0], "renderer": ["17", 2]},
    }
    wf["19"] = {
        "class_type": "Hy3DExportMesh",
        "inputs": {
            "trimesh": ["18", 0],
            "filename_prefix": "3D/textured_multiview",
            "file_format": "glb",
            "save_file": True,
        },
    }
    return wf


if __name__ == "__main__":
    import json

    wf = comfyui_build_textured_3d_multiview_workflow(
        "tex_src_character.png", views=6, octree=384, max_faces=50000
    )
    print(json.dumps(wf, indent=2))
