"""ComfyUI nodes for visually building structured MiniMax H3 prompts."""

from __future__ import annotations

from copy import deepcopy

from .core import FPS, clone_and_append, compile_scene, h3_frame_count, new_scene


CATEGORY = "MiniMax H3/Prompt Studio"
TEXT = {"multiline": True, "default": ""}
DURATION_OPTIONS = [
    f"{seconds} s — {h3_frame_count(seconds)} frames / {h3_frame_count(seconds) / FPS:.3f} s reales"
    for seconds in range(4, 16)
]


def _selected_seconds(value):
    """Accept the new selector labels and remain compatible with older workflows."""
    if isinstance(value, str):
        return int(value.split()[0])
    return int(float(value))


class H3SceneStart:
    @classmethod
    def INPUT_TYPES(cls):
        return {
            "required": {
                "workflow_mode": ([
                    "T2V — texto",
                    "I2V — first frame",
                    "I2V — first + last",
                    "I2V — last frame",
                    "R2V — referencias",
                ],),
                "duration_seconds": (DURATION_OPTIONS, {"default": DURATION_OPTIONS[1]}),
                "style_preset": ([
                    "cinematic realism", "photorealistic", "documentary", "commercial",
                    "fashion film", "anime", "3D animation", "stop motion", "custom",
                ],),
                "custom_style": ("STRING", TEXT),
                "aspect_ratio": (["16:9", "9:16", "1:1", "4:3", "3:4", "21:9"],),
                "scene_objective": ("STRING", TEXT),
                "environment": ("STRING", TEXT),
                "lighting": ("STRING", TEXT),
                "color_palette": ("STRING", TEXT),
                "continuity_rules": ("STRING", TEXT),
                "global_constraints": ("STRING", TEXT),
            }
        }

    RETURN_TYPES = ("H3_SCENE",)
    RETURN_NAMES = ("scene",)
    FUNCTION = "create"
    CATEGORY = CATEGORY

    def create(self, duration_seconds, **values):
        values["duration_seconds"] = _selected_seconds(duration_seconds)
        return (new_scene(**values),)


class H3AddReference:
    @classmethod
    def INPUT_TYPES(cls):
        return {
            "required": {
                "scene": ("H3_SCENE",),
                "enabled": ("BOOLEAN", {"default": True}),
                "source_media": (["image", "video", "audio"],),
                "connected_index": ("INT", {"default": 1, "min": 1, "max": 9}),
                "conceptual_label_type": (["Subject", "Picture", "Video", "Audio"],),
                "conceptual_index": ("INT", {"default": 1, "min": 1, "max": 99}),
                "role": ([
                    "identity", "style", "wardrobe", "environment", "motion", "camera",
                    "edit structure", "voice", "sound", "music", "keyframe",
                ],),
                "definition": ("STRING", TEXT),
                "appears_in_shots": ("STRING", {"default": "1"}),
                "retention_marker": ([
                    "fully_preserved", "partially_preserved", "attribute_transfer", "weak_reference",
                    "fully_copy", "partially_copy", "reference",
                ],),
                "retention_detail": ("STRING", TEXT),
            }
        }

    RETURN_TYPES = ("H3_SCENE",)
    RETURN_NAMES = ("scene",)
    FUNCTION = "add"
    CATEGORY = CATEGORY

    def add(self, scene, enabled, **values):
        if not enabled:
            return (deepcopy(scene),)
        return (clone_and_append(scene, "references", values),)


class H3AddSubject:
    @classmethod
    def INPUT_TYPES(cls):
        return {
            "required": {
                "scene": ("H3_SCENE",),
                "enabled": ("BOOLEAN", {"default": True}),
                "subject_id": ("STRING", {"default": "subject_1"}),
                "name": ("STRING", {"default": "Main subject"}),
                "appearance": ("STRING", TEXT),
                "wardrobe_props": ("STRING", TEXT),
                "initial_position": ("STRING", TEXT),
                "identity_continuity": ("STRING", TEXT),
                "voice_description": ("STRING", TEXT),
            }
        }

    RETURN_TYPES = ("H3_SCENE",)
    RETURN_NAMES = ("scene",)
    FUNCTION = "add"
    CATEGORY = CATEGORY

    def add(self, scene, enabled, **values):
        if not enabled:
            return (deepcopy(scene),)
        return (clone_and_append(scene, "subjects", values),)


class H3AddShot:
    @classmethod
    def INPUT_TYPES(cls):
        return {
            "required": {
                "scene": ("H3_SCENE",),
                "enabled": ("BOOLEAN", {"default": True}),
                "start_seconds": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 15.0, "step": 0.1}),
                "end_seconds": ("FLOAT", {"default": 5.0, "min": 0.1, "max": 15.0, "step": 0.1}),
                "shot_size": ([
                    "extreme wide shot", "wide shot", "full shot", "medium wide shot",
                    "medium shot", "medium close-up", "close-up", "extreme close-up",
                    "over-the-shoulder shot", "point-of-view shot", "aerial shot",
                ],),
                "composition": ("STRING", TEXT),
                "subject_ids": ("STRING", {"default": "subject_1"}),
                "action": ("STRING", TEXT),
                "reaction_end_state": ("STRING", TEXT),
                "camera_type": ([
                    "static camera", "pan left", "pan right", "tilt up", "tilt down",
                    "push in", "pull out", "dolly in", "dolly out", "truck left",
                    "truck right", "pedestal up", "pedestal down", "orbit clockwise",
                    "orbit counterclockwise", "crane shot", "handheld tracking shot",
                    "Steadicam tracking shot", "zoom in", "zoom out", "rack focus",
                ],),
                "camera_amplitude": (["none", "small", "large"],),
                "camera_speed": (["normal", "slow", "fast"],),
                "camera_target": ("STRING", TEXT),
                "transition": (["cut", "cross-dissolve", "fade", "wipe", "match cut"],),
                "lighting_change": ("STRING", TEXT),
                "diegetic_sound": ("STRING", TEXT),
                "on_screen_text": ("STRING", TEXT),
                "reference_cues": ("STRING", TEXT),
            }
        }

    RETURN_TYPES = ("H3_SCENE",)
    RETURN_NAMES = ("scene",)
    FUNCTION = "add"
    CATEGORY = CATEGORY

    def add(self, scene, enabled, **values):
        if not enabled:
            return (deepcopy(scene),)
        return (clone_and_append(scene, "shots", values),)


class H3AddDialogue:
    @classmethod
    def INPUT_TYPES(cls):
        return {
            "required": {
                "scene": ("H3_SCENE",),
                "enabled": ("BOOLEAN", {"default": True}),
                "shot_number": ("INT", {"default": 1, "min": 1, "max": 99}),
                "speaker_subject_id": ("STRING", {"default": "subject_1"}),
                "language": (["Spanish", "English", "Portuguese", "French", "German", "Italian", "Japanese", "Korean", "Chinese", "Other"],),
                "text": ("STRING", TEXT),
                "delivery": ("STRING", TEXT),
                "voiceover": ("BOOLEAN", {"default": False}),
                "singing": ("BOOLEAN", {"default": False}),
                "start_seconds": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 15.0, "step": 0.1}),
                "end_seconds": ("FLOAT", {"default": 2.5, "min": 0.0, "max": 15.0, "step": 0.1}),
                "crosses_cut": ("BOOLEAN", {"default": False}),
                "cutoff": ("BOOLEAN", {"default": False}),
            }
        }

    RETURN_TYPES = ("H3_SCENE",)
    RETURN_NAMES = ("scene",)
    FUNCTION = "add"
    CATEGORY = CATEGORY

    def add(self, scene, enabled, **values):
        if not enabled:
            return (deepcopy(scene),)
        return (clone_and_append(scene, "dialogues", values),)


class H3AudioPlan:
    @classmethod
    def INPUT_TYPES(cls):
        return {
            "required": {
                "scene": ("H3_SCENE",),
                "ambience": ("STRING", TEXT),
                "physical_sounds": ("STRING", TEXT),
                "nonverbal_sounds": ("STRING", TEXT),
                "complete_silence": ("BOOLEAN", {"default": False}),
                "music_enabled": ("BOOLEAN", {"default": False}),
                "instrumentation": ("STRING", TEXT),
                "tempo": ("STRING", TEXT),
                "rhythm": ("STRING", TEXT),
                "dynamics": ("STRING", TEXT),
            }
        }

    RETURN_TYPES = ("H3_SCENE",)
    RETURN_NAMES = ("scene",)
    FUNCTION = "set_audio"
    CATEGORY = CATEGORY

    def set_audio(self, scene, **values):
        result = deepcopy(scene)
        result["audio"] = values
        return (result,)


class H3CompilePrompt:
    @classmethod
    def INPUT_TYPES(cls):
        return {"required": {"scene": ("H3_SCENE",)}}

    RETURN_TYPES = ("STRING", "STRING", "INT")
    RETURN_NAMES = ("prompt", "validation_report", "frames")
    FUNCTION = "compile"
    OUTPUT_NODE = True
    CATEGORY = CATEGORY

    def compile(self, scene):
        prompt, validation, frames = compile_scene(scene)
        report = validation.report(frames)
        return {
            "ui": {"prompt": [prompt], "report": [report]},
            "result": (prompt, report, frames),
        }


NODE_CLASS_MAPPINGS = {
    "H3SceneStart": H3SceneStart,
    "H3AddReference": H3AddReference,
    "H3AddSubject": H3AddSubject,
    "H3AddShot": H3AddShot,
    "H3AddDialogue": H3AddDialogue,
    "H3AudioPlan": H3AudioPlan,
    "H3CompilePrompt": H3CompilePrompt,
}

NODE_DISPLAY_NAME_MAPPINGS = {
    "H3SceneStart": "H3 · 1 Inicio de escena",
    "H3AddReference": "H3 · 2 Agregar referencia R2V",
    "H3AddSubject": "H3 · 3 Agregar sujeto",
    "H3AddShot": "H3 · 4 Agregar plano",
    "H3AddDialogue": "H3 · 5 Agregar diálogo",
    "H3AudioPlan": "H3 · 6 Diseño sonoro y música",
    "H3CompilePrompt": "H3 · 7 Compilar, validar y copiar",
}
