"""FikoYT PuLID v2 Face Apply — Flux icin PuLID identity injection.

ComfyUI_PuLID_Flux_ll node zincirini tek wrapper icinde calistirir:
  PulidFluxModelLoader -> PulidFluxInsightFaceLoader -> PulidFluxEvaClipLoader -> ApplyPulidFlux
Antelopev2 + EVA-CLIP + PuLID modelleri ilk kullanimda auto-download.
"""
import os

try:
    import folder_paths  # noqa: F401
except ImportError:
    folder_paths = None

from ..core import ensure_model, get_models_dir


PULID_FILE = "pulid_flux_v0.9.1.safetensors"

PULID_MODELS = [
    {"repo": "guozinan/PuLID", "file": PULID_FILE, "subdir": "pulid"},
]

EVA_CLIP_MODELS = [
    {"repo": "QuanSun/EVA-CLIP", "file": "EVA02_CLIP_L_336_psz14_s6B.pt", "subdir": "clip"},
]

ANTELOPEV2_MODELS = [
    {"repo": "DIAMONIK7777/antelopev2", "file": "1k3d68.onnx",          "subdir": "insightface/models/antelopev2"},
    {"repo": "DIAMONIK7777/antelopev2", "file": "2d106det.onnx",        "subdir": "insightface/models/antelopev2"},
    {"repo": "DIAMONIK7777/antelopev2", "file": "genderage.onnx",       "subdir": "insightface/models/antelopev2"},
    {"repo": "DIAMONIK7777/antelopev2", "file": "glintr100.onnx",       "subdir": "insightface/models/antelopev2"},
    {"repo": "DIAMONIK7777/antelopev2", "file": "scrfd_10g_bnkps.onnx", "subdir": "insightface/models/antelopev2"},
]


def _download_all(auto_download: bool) -> None:
    if not auto_download:
        return
    for m in PULID_MODELS + EVA_CLIP_MODELS + ANTELOPEV2_MODELS:
        target = os.path.join(get_models_dir(m["subdir"]), m["file"])
        if not os.path.isfile(target):
            ensure_model(m["repo"], m["file"], m["subdir"])


def _resolve_pulid_classes():
    """ComfyUI global registry'sinden PuLID_Flux_ll node siniflarini al.

    Modul adi farkli forklarda degisebilir (pulidflux/nodes); en saglam yol bu.
    """
    try:
        from nodes import NODE_CLASS_MAPPINGS as GM
    except Exception:
        return None
    needed = (
        "PulidFluxModelLoader",
        "PulidFluxInsightFaceLoader",
        "PulidFluxEvaClipLoader",
        "ApplyPulidFlux",
    )
    if not all(k in GM for k in needed):
        return None
    return {k: GM[k] for k in needed}


_CACHE: dict = {}


class FikoYTPuLIDv2:
    @classmethod
    def INPUT_TYPES(cls):
        return {
            "required": {
                "model":         ("MODEL",),
                "face_image":    ("IMAGE",),
                "weight":        ("FLOAT", {"default": 1.0, "min": 0.0, "max": 2.0, "step": 0.05}),
                "start_at":      ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01}),
                "end_at":        ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}),
                "provider":      (["CUDA", "CPU"], {"default": "CUDA"}),
                "auto_download": ("BOOLEAN", {"default": True}),
            }
        }

    RETURN_TYPES = ("MODEL",)
    RETURN_NAMES = ("MODEL",)
    FUNCTION = "apply"
    CATEGORY = "FikoYT/image"

    def apply(self, model, face_image, weight, start_at, end_at, provider, auto_download):
        _download_all(auto_download)

        cls_map = _resolve_pulid_classes()
        if cls_map is None:
            raise RuntimeError(
                "ComfyUI_PuLID_Flux_ll node sinifları NODE_CLASS_MAPPINGS'te yok. "
                "Custom node yuklu degil veya startup'ta import hatasi aldi (konsol loglarına bak)."
            )

        pulid_key = ("pulid", PULID_FILE)
        if pulid_key not in _CACHE:
            (_CACHE[pulid_key],) = cls_map["PulidFluxModelLoader"]().load_model(PULID_FILE)
        pulid_flux = _CACHE[pulid_key]

        face_key = ("face", provider)
        if face_key not in _CACHE:
            (_CACHE[face_key],) = cls_map["PulidFluxInsightFaceLoader"]().load_insightface(provider)
        face_analysis = _CACHE[face_key]

        eva_key = ("eva",)
        if eva_key not in _CACHE:
            (_CACHE[eva_key],) = cls_map["PulidFluxEvaClipLoader"]().load_eva_clip()
        eva_clip = _CACHE[eva_key]

        (out_model,) = cls_map["ApplyPulidFlux"]().apply_pulid_flux(
            model, pulid_flux, eva_clip, face_analysis, face_image, weight, start_at, end_at,
        )
        return (out_model,)


NODE_CLASS_MAPPINGS = {"FikoYTPuLIDv2": FikoYTPuLIDv2}
NODE_DISPLAY_NAME_MAPPINGS = {"FikoYTPuLIDv2": "FikoYT • PuLID v2 Face Apply"}
