from __future__ import annotations

from typing import Any, Callable

try:
    from . import character_config as character_policy
except ImportError:  # Allows local smoke tests with top-level imports.
    import character_config as character_policy


Choose = Callable[[Any, list[tuple[str, str, str]]], tuple[str, str, str]]


def count_phrase(count: int, singular: str, plural: str) -> str:
    words = {
        0: "no",
        1: "one",
        2: "two",
        3: "three",
        4: "four",
        5: "five",
        6: "six",
        7: "seven",
        8: "eight",
        9: "nine",
        10: "ten",
        11: "eleven",
        12: "twelve",
    }
    label = singular if count == 1 else plural
    return f"{words.get(count, str(count))} {label}"


def cast_summary_phrase(women_count: int, men_count: int) -> str:
    women_count = max(0, int(women_count))
    men_count = max(0, int(men_count))
    if women_count + men_count == 0:
        women_count = 1
    person_count = women_count + men_count
    women_label = "woman" if women_count == 1 else "women"
    men_label = "man" if men_count == 1 else "men"
    return f"{women_count} {women_label}, {men_count} {men_label}, {person_count} total adults"


def explicit_character_slot_label(slot: dict[str, Any]) -> str:
    label = str(slot.get("label") or "").strip().upper()
    if label in character_policy.CHARACTER_LABEL_CHOICES and label != "AUTO_CHAIN":
        return label
    return ""


def character_slot_label_map(slots: list[dict[str, Any]]) -> dict[str, dict[str, Any]]:
    label_map: dict[str, dict[str, Any]] = {}
    letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    for subject_type, prefix in (("woman", "Woman"), ("man", "Man")):
        subject_slots = [slot for slot in slots if slot.get("subject_type") == subject_type]
        auto_slots = [slot for slot in subject_slots if not explicit_character_slot_label(slot)]
        for index, slot in enumerate(reversed(auto_slots)):
            if index >= len(letters):
                break
            label_map[f"{prefix} {letters[index]}"] = slot
        for slot in subject_slots:
            explicit = explicit_character_slot_label(slot)
            if explicit:
                label_map[f"{prefix} {explicit}"] = slot
    return label_map


def configured_cast_context(women_count: int, men_count: int) -> dict[str, str]:
    women_count = max(0, int(women_count))
    men_count = max(0, int(men_count))
    if women_count + men_count == 0:
        women_count = 1
    parts = []
    if women_count:
        parts.append(count_phrase(women_count, "adult woman", "adult women"))
    if men_count:
        parts.append(count_phrase(men_count, "adult man", "adult men"))
    subject_phrase = parts[0] if len(parts) == 1 else f"{parts[0]} and {parts[1]}"
    person_count = women_count + men_count
    if person_count == 1:
        scene_kind = "solo adult sexual pose"
    elif person_count == 2:
        scene_kind = "adult couple sex scene"
    elif person_count == 3:
        scene_kind = "adult threesome sex scene"
    else:
        scene_kind = "adult group sex scene"
    return {
        "subject_type": "configured_cast",
        "subject": f"{women_count}w_{men_count}m_sex_scene",
        "subject_phrase": subject_phrase,
        "age": "21+ adults",
        "body": "varied",
        "skin": "",
        "hair": "",
        "eyes": "",
        "body_phrase": "varied adult bodies",
        "women_count": str(women_count),
        "men_count": str(men_count),
        "person_count": str(person_count),
        "cast_summary": cast_summary_phrase(women_count, men_count),
        "scene_kind": scene_kind,
    }


def couple_type_from_counts(
    rng: Any,
    women_count: int,
    men_count: int,
    *,
    choose: Choose,
    couple_types: list[tuple[str, str, str]],
) -> tuple[str, str, str, int, int]:
    women_count = max(0, int(women_count))
    men_count = max(0, int(men_count))
    if women_count >= 2 and men_count == 0:
        return "two women", "two women", "close affectionate couple pose", 2, 0
    if men_count >= 2 and women_count == 0:
        return "two men", "two men", "relaxed romantic couple pose", 0, 2
    if women_count >= 1 and men_count >= 1:
        return "woman and man", "a woman and a man", "playful date-night pose", 1, 1

    primary_subject, subject_phrase, pose = choose(rng, couple_types)
    if primary_subject == "two women":
        return primary_subject, subject_phrase, pose, 2, 0
    if primary_subject == "two men":
        return primary_subject, subject_phrase, pose, 0, 2
    return primary_subject, subject_phrase, pose, 1, 1
