from __future__ import annotations

from typing import Any, Callable

try:
    from . import row_normalization as row_policy
    from . import softcore_text_policy
except ImportError:  # Allows local smoke tests with `python tools/prompt_smoke.py`.
    import row_normalization as row_policy
    import softcore_text_policy


def _labeled_expression_sentence(label: str, expression: Any) -> str:
    expression = str(expression or "").strip()
    if not expression:
        return ""
    return f"{label}: {expression}. "


def _prepend_trigger(prompt: str, trigger: str, enabled: bool) -> str:
    return row_policy.prepend_trigger(prompt, trigger, enabled)


def _combined_negative(base: str, extra: str) -> str:
    return row_policy.combined_negative(base, extra)


def assemble_insta_pair_metadata(
    *,
    active_trigger: str,
    prepend_trigger_to_prompt: bool,
    extra_positive: str,
    extra_negative: str,
    soft_negative_base: str,
    hard_negative_base: str,
    options: dict[str, Any],
    platform_style: str,
    soft_descriptor_sentence: str,
    soft_level: str,
    soft_cast: str,
    soft_cast_presence: str,
    soft_cast_styling_sentence: str,
    soft_row: dict[str, Any],
    soft_camera_scene_sentence: str,
    soft_camera_sentence: str,
    hard_level: str,
    hard_cast: str,
    cast_descriptor_text: str,
    pov_directive: str,
    pov_character_labels: list[str],
    hard_clothing_sentence: str,
    hard_row: dict[str, Any],
    hard_scene: str,
    hard_camera_scene_sentence: str,
    hard_composition: str,
    hard_detail_directive: str,
    hard_camera_sentence: str,
    descriptor: str,
    soft_partner_outfit_text: str,
    soft_partner_styling: dict[str, Any],
    soft_camera_scene_directive: str,
    soft_camera_config: dict[str, Any],
    soft_camera_directive: str,
    hard_camera_scene_directive: str,
    hard_camera_config: dict[str, Any],
    hard_camera_directive: str,
    camera_caption_text: Callable[[dict[str, Any]], str],
    cast_descriptors: list[str],
    character_hardcore_clothing_entries: list[str],
    pov_hardcore_clothing_entries: list[str],
    default_man_hardcore_clothing_entries: list[str],
    hard_clothing_state: str,
    hard_detail_density: str,
    hard_women_count: int,
    hard_men_count: int,
    character_slots: list[dict[str, Any]],
    character_slot_map: dict[str, dict[str, Any]],
) -> dict[str, Any]:
    soft_prompt = (
        f"Insta/OF softcore mode: {platform_style}. "
        f"{soft_descriptor_sentence}"
        f"Softcore setup: {soft_level}. Cast: {soft_cast}. "
        f"{soft_cast_presence}"
        f"{soft_cast_styling_sentence}"
        f"{soft_row['softcore_item_prompt_label']}: {soft_row['item']}. Pose: {soft_row['pose']}. Setting: {soft_row['scene_text']}. "
        f"{soft_camera_scene_sentence}"
        f"{_labeled_expression_sentence('Facial expression', soft_row.get('expression'))}"
        f"Composition: {soft_row['composition']}. "
        f"{soft_camera_sentence}"
        f"{softcore_text_policy.softcore_style_directive()} "
        f"{soft_row['positive_suffix']}."
    )
    hard_prompt = (
        f"Insta/OF hardcore mode: {platform_style}. "
        f"Hardcore setup: {hard_level}. Cast: {hard_cast}. "
        f"Cast descriptors: {cast_descriptor_text}. "
        f"{pov_directive + ' ' if pov_directive else ''}"
        f"{'Keep Woman A visually central from the POV camera. ' if pov_character_labels else 'Keep Woman A visually central. '}"
        f"{hard_clothing_sentence}"
        f"Role graph: {hard_row['role_graph']} Sexual scene: {hard_row['item']}. "
        f"Setting: {hard_scene}. "
        f"{hard_camera_scene_sentence}"
        f"{_labeled_expression_sentence('Facial expressions', hard_row.get('expression'))}"
        f"Composition: {hard_composition}. "
        f"{hard_detail_directive}"
        f"{hard_camera_sentence}"
        f"{hard_row['positive_suffix']}."
    )
    soft_caption_parts = [
        active_trigger,
        "Insta/OF softcore mode",
        descriptor,
        soft_level,
        soft_row["item"],
        soft_row["pose"],
        soft_partner_outfit_text,
        soft_partner_styling["pose"],
        soft_row["scene_text"],
        soft_camera_scene_directive,
        soft_row["composition"],
        camera_caption_text(soft_camera_config) if soft_camera_directive else "",
    ]
    hard_caption_parts = [
        active_trigger,
        "Insta/OF hardcore mode",
        "Woman A",
        descriptor,
        hard_cast,
        hard_row["role_graph"],
        hard_row["item"],
        hard_scene,
        hard_camera_scene_directive,
        hard_composition,
        camera_caption_text(hard_camera_config) if hard_camera_directive else "",
    ]
    normalized_text = row_policy.normalize_pair_text_outputs(
        active_trigger=active_trigger,
        prepend_trigger_to_prompt=bool(prepend_trigger_to_prompt),
        extra_positive=extra_positive,
        extra_negative=extra_negative,
        soft_prompt=soft_prompt,
        hard_prompt=hard_prompt,
        soft_negative_base=soft_negative_base,
        hard_negative_base=hard_negative_base,
        soft_caption_parts=soft_caption_parts,
        hard_caption_parts=hard_caption_parts,
    )

    pair = {
        "mode": "Insta/OF",
        "options": options,
        "shared_descriptor": descriptor,
        "shared_cast_descriptors": cast_descriptors,
        "pov_character_labels": pov_character_labels,
        "pov_prompt_directive": pov_directive,
        "softcore_partner_styling": soft_partner_styling,
        "character_hardcore_clothing": character_hardcore_clothing_entries,
        "pov_hardcore_clothing": pov_hardcore_clothing_entries,
        "default_man_hardcore_clothing": default_man_hardcore_clothing_entries,
        "hardcore_clothing_state": hard_clothing_state,
        "hardcore_detail_density": hard_detail_density,
        "hardcore_position_config": hard_row.get("hardcore_position_config", {}),
        "softcore_prompt": normalized_text["soft_prompt"],
        "hardcore_prompt": normalized_text["hard_prompt"],
        "softcore_negative_prompt": normalized_text["soft_negative"],
        "hardcore_negative_prompt": normalized_text["hard_negative"],
        "softcore_caption": normalized_text["soft_caption"],
        "hardcore_caption": normalized_text["hard_caption"],
        "softcore_row": soft_row,
        "hardcore_row": hard_row,
        "hardcore_women_count": hard_women_count,
        "hardcore_men_count": hard_men_count,
        "character_cast_slots": character_slots,
        "character_slot_labels": sorted(character_slot_map),
        "softcore_camera_config": soft_camera_config,
        "hardcore_camera_config": hard_camera_config,
        "softcore_camera_directive": soft_camera_directive,
        "hardcore_camera_directive": hard_camera_directive,
        "softcore_camera_scene_directive": soft_camera_scene_directive,
        "hardcore_camera_scene_directive": hard_camera_scene_directive,
    }
    return row_policy.normalize_pair_metadata(pair, active_trigger=active_trigger)
