"""FikoYT Character Bind — name + face + lora_stack + refs → FIKOYT_CHARACTER bundle."""
import os
import time

try:
    import numpy as np
    from PIL import Image
except ImportError:
    np = None
    Image = None

from ..core import FIKOYT_CHARACTER, FIKOYT_LORA_STACK, make_character, get_models_dir


def _output_dir() -> str:
    try:
        import folder_paths
        base = folder_paths.get_output_directory()
    except Exception:
        here = os.path.dirname(os.path.abspath(__file__))
        base = os.path.abspath(os.path.join(here, "..", "..", "..", "..", "output"))
    out = os.path.join(base, "fikoyt", "characters")
    os.makedirs(out, exist_ok=True)
    return out


def _tensor_to_pil(image):
    """ComfyUI IMAGE tensor (B,H,W,C float[0..1]) → PIL Image (ilk batch)."""
    if image is None or np is None or Image is None:
        return None
    arr = image[0].detach().cpu().numpy() if hasattr(image, "detach") else np.asarray(image)[0]
    arr = np.clip(arr * 255.0, 0, 255).astype("uint8")
    return Image.fromarray(arr)


class FikoYTCharacterBind:
    @classmethod
    def INPUT_TYPES(cls):
        return {
            "required": {
                "name": ("STRING", {"default": "character_01"}),
                "base_prompt": ("STRING", {"default": "", "multiline": True}),
                "base_neg": ("STRING", {"default": "", "multiline": True}),
            },
            "optional": {
                "face_image": ("IMAGE",),
                "ref_image": ("IMAGE",),
                "lora_stack": (FIKOYT_LORA_STACK,),
            },
        }

    RETURN_TYPES = (FIKOYT_CHARACTER,)
    RETURN_NAMES = ("character",)
    FUNCTION = "bind"
    CATEGORY = "FikoYT/character"

    def bind(self, name, base_prompt, base_neg, face_image=None, ref_image=None, lora_stack=None):
        safe = "".join(c for c in str(name).strip() if c.isalnum() or c in ("_", "-")) or "character"
        out_dir = _output_dir()

        face_path = ""
        if face_image is not None:
            pil = _tensor_to_pil(face_image)
            if pil is not None:
                face_path = os.path.join(out_dir, f"{safe}_face.png")
                pil.save(face_path, "PNG")

        ref_path = ""
        if ref_image is not None:
            pil = _tensor_to_pil(ref_image)
            if pil is not None:
                ref_path = os.path.join(out_dir, f"{safe}_ref_{int(time.time())}.png")
                pil.save(ref_path, "PNG")

        lora_paths = []
        if lora_stack:
            for item in lora_stack:
                if isinstance(item, dict) and item.get("name"):
                    lora_paths.append(item["name"])

        bundle = make_character(
            name=safe,
            face_emb_path=face_path,
            lora_paths=lora_paths,
            ref_image_path=ref_path,
            base_prompt=base_prompt or "",
            base_neg=base_neg or "",
        )
        # Tam LoRA stack'i de bundle içine ek olarak saklayalım (Unpack tarafında yeniden kullanılır).
        bundle["lora_stack"] = list(lora_stack or [])
        return (bundle,)


NODE_CLASS_MAPPINGS = {"FikoYTCharacterBind": FikoYTCharacterBind}
NODE_DISPLAY_NAME_MAPPINGS = {"FikoYTCharacterBind": "FikoYT • Character Bind"}
