from __future__ import annotations

from typing import Any, Mapping


CAMERA_DIRECTIONS = (
    "front-right quarter view",
    "right side view",
    "back-right quarter view",
    "back view",
    "back-left quarter view",
    "left side view",
    "front-left quarter view",
    "front view",
)

CAMERA_ELEVATIONS = ("low-angle shot", "eye-level shot", "elevated shot", "high-angle shot")
CAMERA_DISTANCES = (
    "wide shot",
    "full-body shot",
    "three-quarter body shot",
    "medium shot",
    "close-up",
    "extreme close-up",
)


SCENE_CAMERA_PROFILES: tuple[dict[str, Any], ...] = (
    {
        "key": "business_cafe",
        "family": "coworking",
        "terms": ("business cafe", "work cafe", "coworking counter", "cafe counter with laptops", "coffee-counter work spots"),
        "layout_label": "Business cafe camera layout",
        "place": "business cafe coworking counter",
        "foreground": "counter edge, laptop corner, and small plant",
        "midground": "bar stools, warm desk lamps, and coffee-counter work spots",
        "background": "plants, mirror strip, menu wall, and repeated cafe work tables",
        "detail_label": "cafe details",
        "composition": {
            "woman": "business-cafe selfie frame with the woman near a counter edge and warm work-table depth behind her",
            "man": "business-cafe portrait frame with the man near a counter edge and warm work-table depth behind him",
            "default": "business-cafe frame with the subjects near a counter edge and warm work-table depth behind them",
        },
    },
    {
        "key": "office_after_hours",
        "family": "coworking",
        "terms": ("corporate office", "office after hours", "copier", "office lounge"),
        "layout_label": "Office camera layout",
        "place": "empty after-hours office",
        "foreground": "copier alcove edge, chair backs, and nearest desk corner",
        "midground": "repeating desks, glass partition seams, and muted monitor glow",
        "background": "rows of empty workstations, city-light windows, and quiet office depth",
        "detail_label": "office details",
        "composition": {
            "woman": "after-hours office frame with the woman near a desk edge and glass-partition depth behind her",
            "man": "after-hours office frame with the man near a desk edge and glass-partition depth behind him",
            "default": "after-hours office frame with the subjects near a desk edge and glass-partition depth behind them",
        },
    },
    {
        "key": "coworking_lounge",
        "family": "coworking",
        "terms": (
            "coworking",
            "cowork",
            "shared office",
            "laptops",
            "warm desks",
            "repeating desks",
            "glass partitions",
        ),
        "layout_label": "Coworking camera layout",
        "place": "coworking lounge",
        "foreground": "near desk edge, laptop corner, and chair back",
        "midground": "warm work desks, laptop tables, and glass partition seams",
        "background": "tall windows, repeated desk rows, plants, and soft shared-office depth",
        "detail_label": "coworking details",
        "composition": {
            "woman": "coworking lounge selfie frame with the woman near a desk edge and tall-window depth behind her",
            "man": "coworking lounge portrait frame with the man near a desk edge and tall-window depth behind him",
            "default": "coworking lounge frame with the subjects near a desk edge and tall-window depth behind them",
        },
    },
    {
        "key": "classical_library",
        "family": "library",
        "terms": (
            "classical library",
            "library stacks",
            "large library",
            "grand library",
            "reading room",
            "book stacks",
            "rare-books",
            "rare books",
            "rolling ladders",
        ),
        "layout_label": "Library camera layout",
        "place": "classical library",
        "foreground": "near bookshelf edge, reading-table corner, and brass lamp",
        "midground": "towering bookshelves, rolling ladders, carved columns, and marble floor lines",
        "background": "arched windows, repeated book aisles, warm brass lamps, and deep quiet library depth",
        "detail_label": "library details",
        "composition": {
            "woman": "classical library frame with the woman near a bookshelf edge and long shelf depth behind her",
            "man": "classical library frame with the man near a bookshelf edge and long shelf depth behind him",
            "default": "classical library frame with the subjects near a bookshelf edge and long shelf depth behind them",
        },
    },
    {
        "key": "creator_bedroom",
        "family": "private_creator",
        "terms": (
            "creator bedroom",
            "content setup",
            "phone tripod",
            "ring light",
            "phone on a mini tripod",
            "creator studio",
            "creator-shot framing",
            "vertical creator-video",
        ),
        "layout_label": "Creator room camera layout",
        "place": "private creator room",
        "foreground": "bed edge, phone tripod, and rumpled sheets",
        "midground": "ring light stand, warm lamps, pillows, and creator props",
        "background": "soft bedding, curtains, mirror edge, and warm private-room depth",
        "detail_label": "creator-room details",
        "composition": {
            "woman": "creator-room frame with the woman near the bed edge and phone-tripod setup behind her",
            "man": "creator-room frame with the man near the bed edge and phone-tripod setup behind him",
            "default": "creator-room frame with the subjects near the bed edge and phone-tripod setup behind them",
        },
    },
    {
        "key": "mirror_room",
        "family": "private_creator",
        "terms": (
            "mirror selfie setup",
            "mirror wall",
            "mirror-facing",
            "floor mirror",
            "vanity mirror",
            "phone reflection",
            "reflected bodies",
            "black lacquer mirror",
            "neon mirror wall",
        ),
        "layout_label": "Mirror-room camera layout",
        "place": "private mirror room",
        "foreground": "mirror edge, reflected phone angle, and floor reflection line",
        "midground": "bedside surface, vanity bulbs, glossy furniture, and reflected body plane",
        "background": "mirror depth, warm lamps, curtains, and repeated reflected sightlines",
        "detail_label": "mirror-room details",
        "composition": {
            "woman": "mirror-room frame with the woman aligned to the reflected phone angle and room depth behind her",
            "man": "mirror-room frame with the man aligned to the reflected phone angle and room depth behind him",
            "default": "mirror-room frame with the subjects aligned to the reflected phone angle and room depth behind them",
        },
    },
    {
        "key": "boudoir_bedroom",
        "family": "private_creator",
        "terms": (
            "boudoir bedroom",
            "silk-sheet bed",
            "silk sheets",
            "velvet headboard",
            "canopy bed",
            "four-poster bed",
            "satin bedding",
            "bedside phone",
            "hotel bedroom",
        ),
        "layout_label": "Boudoir bedroom camera layout",
        "place": "boudoir bedroom",
        "foreground": "sheet fold, bedside edge, and pillow line",
        "midground": "rumpled bedding, warm lamps, canopy curtains, and soft floor shadows",
        "background": "headboard, drapes, mirror edge, and intimate bedroom depth",
        "detail_label": "bedroom details",
        "composition": {
            "woman": "boudoir bedroom frame with the woman on or beside the bed and warm bedroom depth behind her",
            "man": "boudoir bedroom frame with the man on or beside the bed and warm bedroom depth behind him",
            "default": "boudoir bedroom frame with the subjects on or beside the bed and warm bedroom depth behind them",
        },
    },
    {
        "key": "bathroom_shower",
        "family": "private_creator",
        "terms": (
            "bathroom counter",
            "private bathroom",
            "shower room",
            "wet tile",
            "steam",
            "steamy",
            "glass reflections",
            "vanity counter",
            "wet towels",
        ),
        "layout_label": "Bathroom camera layout",
        "place": "private bathroom",
        "foreground": "counter edge, glass partition line, and towel edge",
        "midground": "mirror haze, vanity bulbs, wet tile, and reflected glass seams",
        "background": "shower wall, warm reflected light, steam, and tight private-room depth",
        "detail_label": "bathroom details",
        "composition": {
            "woman": "bathroom frame with the woman near the mirror or glass partition and tile depth behind her",
            "man": "bathroom frame with the man near the mirror or glass partition and tile depth behind him",
            "default": "bathroom frame with the subjects near the mirror or glass partition and tile depth behind them",
        },
    },
    {
        "key": "private_studio",
        "family": "private_creator",
        "terms": (
            "fetish studio",
            "private studio",
            "glossy black floor",
            "harness-wall",
            "chrome studio",
            "industrial loft",
            "neon-lit lacquer",
            "reflective panels",
            "controlled rim light",
        ),
        "layout_label": "Private studio camera layout",
        "place": "private studio set",
        "foreground": "floor reflection edge, prop stand, and lighting-stand line",
        "midground": "controlled lights, reflective panels, backdrop seams, and studio props",
        "background": "dark curtains, glossy walls, rim light, and staged private-set depth",
        "detail_label": "studio details",
        "composition": {
            "woman": "private studio frame with the woman on the glossy floor plane and controlled lights behind her",
            "man": "private studio frame with the man on the glossy floor plane and controlled lights behind him",
            "default": "private studio frame with the subjects on the glossy floor plane and controlled lights behind them",
        },
    },
    {
        "key": "car_interior",
        "family": "private_creator",
        "terms": (
            "parked car interior",
            "private car backseat",
            "car backseat",
            "dashboard glow",
            "tinted windows",
            "seat reflections",
        ),
        "layout_label": "Car interior camera layout",
        "place": "parked car interior",
        "foreground": "seat edge, door frame, and dashboard glow",
        "midground": "upholstery seams, window reflections, center console, and tight cabin geometry",
        "background": "tinted windows, rear seat depth, and enclosed car interior shadows",
        "detail_label": "car-interior details",
        "composition": {
            "woman": "car interior frame with the woman inside the tight cabin geometry and window reflections behind her",
            "man": "car interior frame with the man inside the tight cabin geometry and window reflections behind him",
            "default": "car interior frame with the subjects inside the tight cabin geometry and window reflections behind them",
        },
    },
    {
        "key": "hotel_corridor",
        "family": "semi_public",
        "terms": (
            "hotel corridor",
            "hotel service corridor",
            "hotel service alcove",
            "service alcove",
            "service hallway",
            "service hall",
            "repeating numbered doors",
            "numbered doors",
            "luggage carts",
            "stair landing",
            "hotel stair landing",
        ),
        "layout_label": "Hotel corridor camera layout",
        "place": "hotel corridor",
        "foreground": "nearest doorframe edge, patterned carpet line, and wall sconce",
        "midground": "repeating numbered doors, brass wall lamps, service-alcove turns, and luggage carts",
        "background": "long corridor perspective, closed doors, warm late-night depth, and quiet hotel sightlines",
        "detail_label": "hotel corridor details",
        "composition": {
            "woman": "hotel corridor frame with the woman near a doorframe edge and repeated doors behind her",
            "man": "hotel corridor frame with the man near a doorframe edge and repeated doors behind him",
            "default": "hotel corridor frame with the subjects near a doorframe edge and repeated doors behind them",
        },
    },
    {
        "key": "parking_garage",
        "family": "semi_public",
        "terms": (
            "parking garage",
            "parking deck",
            "underground garage",
            "multi-level parking",
            "concrete pillars",
            "numbered pillars",
            "painted floor lines",
            "painted bay lines",
            "parked cars",
        ),
        "layout_label": "Parking garage camera layout",
        "place": "parking garage",
        "foreground": "nearest concrete pillar, painted floor line, and car bumper edge",
        "midground": "repeating concrete pillars, parked cars, painted bay lines, and glossy concrete lanes",
        "background": "shadowed corners, fluorescent depth, numbered pillars, and long garage perspective",
        "detail_label": "parking garage details",
        "composition": {
            "woman": "parking garage frame with the woman beside a concrete pillar and repeated bay lines behind her",
            "man": "parking garage frame with the man beside a concrete pillar and repeated bay lines behind him",
            "default": "parking garage frame with the subjects beside a concrete pillar and repeated bay lines behind them",
        },
    },
    {
        "key": "theater_backstage",
        "family": "semi_public",
        "terms": (
            "theater backstage",
            "backstage wings",
            "cabaret backstage",
            "prop storage",
            "prop racks",
            "costume racks",
            "costume rails",
            "stage ropes",
            "scenery flats",
        ),
        "layout_label": "Backstage camera layout",
        "place": "theater backstage",
        "foreground": "curtain edge, prop trunk corner, and costume-rack line",
        "midground": "layered velvet curtains, costume racks, prop shelves, and vanity bulb mirrors",
        "background": "dark stage wings, repeated scenery flats, narrow backstage passages, and warm light spill",
        "detail_label": "backstage details",
        "composition": {
            "woman": "backstage frame with the woman partly framed by curtains and costume racks behind her",
            "man": "backstage frame with the man partly framed by curtains and costume racks behind him",
            "default": "backstage frame with the subjects partly framed by curtains and costume racks behind them",
        },
    },
    {
        "key": "wine_cellar",
        "family": "semi_public",
        "terms": (
            "wine cellar",
            "wine storage",
            "bottle racks",
            "bottle shelves",
            "arched cellar",
            "brick niches",
            "cellar corridor",
            "stacked bottle",
        ),
        "layout_label": "Wine cellar camera layout",
        "place": "wine cellar",
        "foreground": "near bottle-rack edge, crate corner, and stone floor line",
        "midground": "repeating bottle racks, arched brick niches, narrow aisles, and low amber lamps",
        "background": "cool shadowed depth, stacked shelves, cellar arches, and secluded rack rows",
        "detail_label": "wine cellar details",
        "composition": {
            "woman": "wine cellar frame with the woman between bottle racks and arched cellar depth behind her",
            "man": "wine cellar frame with the man between bottle racks and arched cellar depth behind him",
            "default": "wine cellar frame with the subjects between bottle racks and arched cellar depth behind them",
        },
    },
    {
        "key": "museum_archive",
        "family": "semi_public",
        "terms": (
            "museum archive",
            "gallery storage",
            "rare-books archive",
            "archive room",
            "storage shelves",
            "labeled boxes",
            "rolling shelves",
            "catalog drawers",
            "compact shelving",
        ),
        "layout_label": "Archive camera layout",
        "place": "museum archive",
        "foreground": "storage-shelf edge, archive box corner, and work-table line",
        "midground": "labeled boxes, rolling shelves, frame racks, catalog drawers, and long work tables",
        "background": "compact shelving rows, soft overhead lights, archival aisles, and hidden storage depth",
        "detail_label": "archive details",
        "composition": {
            "woman": "archive frame with the woman beside labeled storage shelves and compact rows behind her",
            "man": "archive frame with the man beside labeled storage shelves and compact rows behind him",
            "default": "archive frame with the subjects beside labeled storage shelves and compact rows behind them",
        },
    },
    {
        "key": "laundromat_late_night",
        "family": "semi_public",
        "terms": (
            "laundromat",
            "coin laundry",
            "washing machines",
            "stacked dryers",
            "washer-door",
            "washer door",
            "folding tables",
            "detergent shelves",
            "machine row",
        ),
        "layout_label": "Laundromat camera layout",
        "place": "late-night laundromat",
        "foreground": "folding-table edge, chrome washer door, and tiled floor line",
        "midground": "repeating washing machines, stacked dryers, detergent shelves, and empty machine rows",
        "background": "cool fluorescent depth, mirrored machine doors, front glass, and quiet back-corner sightlines",
        "detail_label": "laundromat details",
        "composition": {
            "woman": "laundromat frame with the woman near a folding table and repeated washer doors behind her",
            "man": "laundromat frame with the man near a folding table and repeated washer doors behind him",
            "default": "laundromat frame with the subjects near a folding table and repeated washer doors behind them",
        },
    },
    {
        "key": "train_station_lockers",
        "family": "semi_public",
        "terms": (
            "train-station locker",
            "train station locker",
            "locker corridor",
            "station underpass",
            "station service passage",
            "metal lockers",
            "vending machines",
            "utility doors",
            "warning stripes",
        ),
        "layout_label": "Station locker camera layout",
        "place": "train-station locker corridor",
        "foreground": "locker edge, vending-machine corner, and tiled floor line",
        "midground": "repeating metal lockers, tiled wall seams, poster frames, and utility doors",
        "background": "fluorescent underpass depth, stair railings, warning stripes, and hidden side alcoves",
        "detail_label": "station locker details",
        "composition": {
            "woman": "station locker frame with the woman beside metal lockers and tiled depth behind her",
            "man": "station locker frame with the man beside metal lockers and tiled depth behind him",
            "default": "station locker frame with the subjects beside metal lockers and tiled depth behind them",
        },
    },
    {
        "key": "nightclub_back_hall",
        "family": "semi_public",
        "terms": (
            "nightclub back hallway",
            "club vip corridor",
            "vip club corridor",
            "music venue greenroom",
            "greenroom corridor",
            "coat-check racks",
            "neon strips",
            "velvet ropes",
            "mirrored wall panels",
            "stickered doors",
        ),
        "layout_label": "Nightclub back-hall camera layout",
        "place": "nightclub back hallway",
        "foreground": "black door edge, velvet-rope post, and mirrored wall strip",
        "midground": "repeated dark doors, neon strips, coat-check racks, mirrored panels, and booth edges",
        "background": "distant colored dance-floor light, dim practical lamps, cable cases, and narrow hallway depth",
        "detail_label": "nightclub back-hall details",
        "composition": {
            "woman": "nightclub back-hall frame with the woman near a dark door edge and neon hallway depth behind her",
            "man": "nightclub back-hall frame with the man near a dark door edge and neon hallway depth behind him",
            "default": "nightclub back-hall frame with the subjects near a dark door edge and neon hallway depth behind them",
        },
    },
    {
        "key": "restaurant_private_booth",
        "family": "semi_public",
        "terms": (
            "restaurant private booth",
            "private booth",
            "bistro back corner",
            "after-hours dining",
            "afterhours dining",
            "high banquettes",
            "dark wood partitions",
            "folded napkins",
            "stacked chairs",
            "small round tables",
        ),
        "layout_label": "Restaurant booth camera layout",
        "place": "restaurant private booth",
        "foreground": "table edge, high banquette back, and dark wood partition",
        "midground": "repeating table lamps, folded napkins, mirrored wall panels, and empty tables",
        "background": "after-hours dining-room depth, stacked chairs, service doorway, and secluded sightlines",
        "detail_label": "restaurant booth details",
        "composition": {
            "woman": "restaurant booth frame with the woman beside a high banquette and table lamps behind her",
            "man": "restaurant booth frame with the man beside a high banquette and table lamps behind him",
            "default": "restaurant booth frame with the subjects beside a high banquette and table lamps behind them",
        },
    },
)

SCENE_CAMERA_PROFILE_KEYS = {str(profile["key"]): dict(profile) for profile in SCENE_CAMERA_PROFILES}

THEME_PROFILE_KEYS = {
    "classical_library": "classical_library",
    "creator_bedroom": "creator_bedroom",
    "mirror_room": "mirror_room",
    "boudoir_bedroom": "boudoir_bedroom",
    "bathroom_shower": "bathroom_shower",
    "private_studio": "private_studio",
    "car_interior": "car_interior",
    "fetish_studio": "private_studio",
    "hotel_corridor": "hotel_corridor",
    "parking_garage": "parking_garage",
    "theater_backstage": "theater_backstage",
    "wine_cellar": "wine_cellar",
    "museum_archive": "museum_archive",
    "laundromat_late_night": "laundromat_late_night",
    "train_station_lockers": "train_station_lockers",
    "nightclub_back_hall": "nightclub_back_hall",
    "restaurant_private_booth": "restaurant_private_booth",
}

SCENE_SLUG_PROFILE_KEYS = {
    "coworking_lounge_window": "coworking_lounge",
    "business_cafe_counter": "business_cafe",
    "office_afterhours_affair": "office_after_hours",
    "classical_large_library": "classical_library",
    "old_world_reading_room": "classical_library",
    "hidden_library_stacks": "classical_library",
    "library_stacks_secret": "classical_library",
    "creator_bedroom_ring_light": "creator_bedroom",
    "onlyfans_mirror_bedroom": "mirror_room",
    "walk_in_closet_tryon": "mirror_room",
    "hotel_bed_phone_tripod": "creator_bedroom",
    "bathroom_counter_selfie": "bathroom_shower",
    "vanity_ring_light_close": "mirror_room",
    "apartment_floor_content": "creator_bedroom",
    "balcony_phone_selfie": "creator_bedroom",
    "car_interior_creator_selfie": "car_interior",
    "shower_steam_phone_reflection": "bathroom_shower",
    "studio_bedroom_backdrop": "creator_bedroom",
    "couch_lamp_creator_clip": "creator_bedroom",
    "large_bedroom_mirror_selfie": "mirror_room",
    "antique_mirror_boudoir": "mirror_room",
    "bathroom_mirror_haze": "bathroom_shower",
    "closet_full_length_mirror": "mirror_room",
    "hotel_mirror_city_view": "mirror_room",
    "neon_mirror_wall": "mirror_room",
    "gold_vanity_mirror": "mirror_room",
    "black_lacquer_mirror_room": "mirror_room",
    "hardcore_bedroom_mirror_pair": "mirror_room",
    "hardcore_hotel_mirror_pair": "mirror_room",
    "hardcore_shower_mirror_pair": "bathroom_shower",
    "hardcore_threesome_mirror_suite": "mirror_room",
    "warm_boudoir_canopy_bed": "boudoir_bedroom",
    "silk_bed_close_creator": "boudoir_bedroom",
    "velvet_headboard_bedroom": "boudoir_bedroom",
    "four_poster_lingerie_room": "boudoir_bedroom",
    "hotel_satin_bedroom": "boudoir_bedroom",
    "rose_lamp_bedroom": "boudoir_bedroom",
    "black_latex_studio_floor": "private_studio",
    "red_velvet_lacquer_room": "private_studio",
    "industrial_loft_private_set": "private_studio",
    "neon_lacquer_private_room": "private_studio",
    "harness_wall_studio": "private_studio",
    "chrome_fetish_set": "private_studio",
    "costume_dressing_room_phone": "theater_backstage",
    "burlesque_stage_close": "theater_backstage",
    "cabaret_backstage_vanity": "theater_backstage",
    "after_dark_private_office": "office_after_hours",
    "fantasy_parlor_content_set": "private_studio",
    "cosplay_hotel_mirror": "mirror_room",
    "hardcore_bedroom_phone_tripod": "creator_bedroom",
    "hardcore_hotel_bed_city": "boudoir_bedroom",
    "hardcore_mirror_bedroom": "mirror_room",
    "hardcore_low_mattress_studio": "private_studio",
    "hardcore_velvet_room": "private_studio",
    "hardcore_shower_room": "bathroom_shower",
    "hardcore_lounge_couch": "private_studio",
    "hardcore_floor_cushion_room": "boudoir_bedroom",
    "hardcore_ring_light_bed": "creator_bedroom",
    "hardcore_bathroom_counter": "bathroom_shower",
    "hardcore_walk_in_closet_floor": "mirror_room",
    "hardcore_car_backseat": "car_interior",
    "bed_edge_close_contact": "boudoir_bedroom",
    "low_bed_mirror_angle": "mirror_room",
    "hotel_bed_overhead": "boudoir_bedroom",
    "floor_mattress_creator_set": "creator_bedroom",
    "canopy_bed_explicit_set": "boudoir_bedroom",
    "velvet_bedroom_wide": "boudoir_bedroom",
    "penetration_mirror_bedroom": "mirror_room",
    "penetration_edge_of_bed": "boudoir_bedroom",
    "penetration_low_mattress": "private_studio",
    "penetration_couch_lounge": "private_studio",
    "penetration_shower_bench": "bathroom_shower",
    "penetration_floor_cushions": "boudoir_bedroom",
    "oral_bed_kneeling_close": "boudoir_bedroom",
    "oral_mirror_floor": "mirror_room",
    "oral_couch_front_view": "private_studio",
    "oral_shower_steam": "bathroom_shower",
    "oral_vanity_floor": "mirror_room",
    "oral_hotel_bed_close": "boudoir_bedroom",
    "anal_rear_mirror_bed": "mirror_room",
    "anal_bent_over_couch": "private_studio",
    "anal_edge_bed_low_angle": "boudoir_bedroom",
    "anal_shower_wall": "bathroom_shower",
    "anal_velvet_bench": "private_studio",
    "anal_floor_mattress_mirror": "mirror_room",
    "threesome_wide_bedroom": "boudoir_bedroom",
    "threesome_hotel_suite": "boudoir_bedroom",
    "threesome_floor_cushions": "boudoir_bedroom",
    "threesome_studio_mattress": "private_studio",
    "threesome_shower_room": "bathroom_shower",
    "threesome_velvet_lounge": "private_studio",
    "group_suite_wide_bed": "boudoir_bedroom",
    "group_studio_mattress_room": "private_studio",
    "group_velvet_orgy_room": "private_studio",
    "group_lounge_couches": "private_studio",
    "group_floor_pillow_room": "boudoir_bedroom",
    "group_shower_spa_room": "bathroom_shower",
    "group_rooftop_private_party": "creator_bedroom",
    "group_hotel_party_bedroom": "boudoir_bedroom",
    "group_backstage_private_room": "theater_backstage",
    "group_neon_loft_room": "private_studio",
    "group_mirror_wall_suite": "mirror_room",
    "group_lacquer_mirror_lounge": "mirror_room",
    "climax_bed_close_flash": "boudoir_bedroom",
    "climax_mirror_counter": "mirror_room",
    "climax_floor_sheets": "boudoir_bedroom",
    "climax_hotel_bed_flash": "boudoir_bedroom",
    "climax_shower_tile": "bathroom_shower",
    "climax_velvet_couch": "private_studio",
}

PROFILE_TEXT_FIELDS = (
    "key",
    "family",
    "layout_label",
    "place",
    "foreground",
    "midground",
    "background",
    "detail_label",
)

MISMATCHED_COMPOSITION_TERMS = (
    "camera-aware",
    "camera aware",
    "outfit-check",
    "outfit check",
    "mirror view",
    "mirror pose",
    "bag",
    "shoes",
    "footwear",
)


def _clean_text(value: Any) -> str:
    return " ".join(str(value or "").strip().split())


def _profile_by_key(value: Any) -> dict[str, Any]:
    key = str(value or "").strip()
    if not key:
        return {}
    if key in SCENE_CAMERA_PROFILE_KEYS:
        return dict(SCENE_CAMERA_PROFILE_KEYS[key])
    mapped_key = THEME_PROFILE_KEYS.get(key)
    if mapped_key and mapped_key in SCENE_CAMERA_PROFILE_KEYS:
        return dict(SCENE_CAMERA_PROFILE_KEYS[mapped_key])
    return {}


def _profile_title(value: str) -> str:
    text = _clean_text(value).replace("_", " ").replace("-", " ")
    if not text:
        return "Scene"
    return " ".join(part[:1].upper() + part[1:] for part in text.split())


def _default_composition(profile: dict[str, Any]) -> dict[str, str]:
    place = _clean_text(profile.get("place")) or "scene"
    foreground = _clean_text(profile.get("foreground")) or "foreground anchor"
    background = _clean_text(profile.get("background")) or "environment depth"
    return {
        "woman": f"{place} frame with the woman near {foreground} and {background} behind her",
        "man": f"{place} frame with the man near {foreground} and {background} behind him",
        "default": f"{place} frame with the subjects near {foreground} and {background} behind them",
    }


def normalize_scene_camera_profile(value: Any) -> dict[str, Any]:
    if not isinstance(value, dict):
        return {}
    base = _profile_by_key(value.get("base_profile_key") or value.get("extends"))
    merged = dict(base)
    for key, raw_value in value.items():
        if key in ("base_profile_key", "extends"):
            continue
        merged[key] = raw_value
    has_profile_fields = any(_clean_text(merged.get(key)) for key in ("layout_label", "place", "foreground", "midground", "background"))
    if not has_profile_fields:
        return {}
    key = _clean_text(merged.get("key") or merged.get("slug") or merged.get("name") or base.get("key") or "custom_scene")
    place = _clean_text(merged.get("place") or merged.get("name") or key.replace("_", " "))
    profile = {field: _clean_text(merged.get(field)) for field in PROFILE_TEXT_FIELDS}
    profile["key"] = key
    profile["family"] = profile["family"] or "custom"
    profile["place"] = place
    profile["layout_label"] = profile["layout_label"] or f"{_profile_title(place)} camera layout"
    profile["foreground"] = profile["foreground"] or base.get("foreground", "foreground anchor")
    profile["midground"] = profile["midground"] or base.get("midground", "midground environment anchors")
    profile["background"] = profile["background"] or base.get("background", "background depth")
    profile["detail_label"] = profile["detail_label"] or f"{place} details"
    composition = merged.get("composition")
    if isinstance(composition, dict):
        profile["composition"] = {
            str(key): _clean_text(text)
            for key, text in composition.items()
            if _clean_text(text)
        }
    else:
        base_composition = base.get("composition") if isinstance(base.get("composition"), dict) else {}
        profile["composition"] = dict(base_composition) if base_composition else _default_composition(profile)
    if not profile["composition"]:
        profile["composition"] = _default_composition(profile)
    return profile


def _scene_entry_text(scene_entry: Any) -> str:
    if not isinstance(scene_entry, dict):
        return ""
    return str(
        scene_entry.get("prompt")
        or scene_entry.get("description")
        or scene_entry.get("text")
        or scene_entry.get("name")
        or ""
    ).strip()


def _scene_entry_profile_key(scene_entry: Any) -> str:
    if not isinstance(scene_entry, dict):
        return ""
    explicit = str(
        scene_entry.get("scene_camera_profile_key")
        or scene_entry.get("camera_profile_key")
        or scene_entry.get("camera_profile")
        or scene_entry.get("profile")
        or ""
    ).strip()
    if explicit:
        return explicit
    slug = str(scene_entry.get("slug") or "").strip()
    return SCENE_SLUG_PROFILE_KEYS.get(slug, "")


def _scene_entry_profile(scene_entry: Any) -> dict[str, Any]:
    if not isinstance(scene_entry, dict):
        return {}
    for key in ("scene_camera_profile", "camera_profile"):
        profile = normalize_scene_camera_profile(scene_entry.get(key))
        if profile:
            return profile
    profile = normalize_scene_camera_profile(scene_entry.get("profile"))
    if profile:
        return profile
    return normalize_scene_camera_profile(scene_entry)


def scene_camera_profile(
    scene_text: Any = "",
    *,
    scene_entry: Any = None,
    theme: Any = "",
    profile_key: Any = "",
) -> dict[str, Any]:
    inline_explicit_profile = normalize_scene_camera_profile(profile_key)
    if inline_explicit_profile:
        return inline_explicit_profile
    explicit_profile = _profile_by_key(profile_key)
    if explicit_profile:
        return explicit_profile
    inline_entry_profile = _scene_entry_profile(scene_entry)
    if inline_entry_profile:
        return inline_entry_profile
    entry_profile = _profile_by_key(_scene_entry_profile_key(scene_entry))
    if entry_profile:
        return entry_profile
    theme_profile = _profile_by_key(theme)
    if theme_profile:
        return theme_profile
    if isinstance(scene_entry, dict):
        entry_theme_profile = _profile_by_key(scene_entry.get("theme"))
        if entry_theme_profile:
            return entry_theme_profile
    text = " ".join(part for part in (str(scene_text or ""), _scene_entry_text(scene_entry)) if part).lower()
    if not text:
        return {}
    for profile in SCENE_CAMERA_PROFILES:
        if any(term in text for term in profile["terms"]):
            return dict(profile)
    return {}


def is_coworking_scene(scene_text: Any) -> bool:
    return scene_camera_profile(scene_text).get("family") == "coworking"


def is_scene_camera_aware(scene_text: Any) -> bool:
    return bool(scene_camera_profile(scene_text))


def _compact_label(value: Any, compact_labels: Mapping[str, str] | None = None) -> str:
    text = str(value or "")
    if compact_labels and text in compact_labels:
        return compact_labels[text]
    return text.replace("_", " ")


def camera_geometry_phrase(parsed: dict[str, Any], compact_labels: Mapping[str, str] | None = None) -> str:
    direction = str(parsed.get("orbit_direction") or "").strip()
    elevation = str(parsed.get("orbit_elevation_label") or "").strip()
    distance = str(parsed.get("orbit_distance_label") or "").strip()
    custom = str(parsed.get("custom_camera_prompt") or "").strip()
    if not any((direction, elevation, distance)) and custom:
        return custom
    parts = [part for part in (direction, elevation, distance) if part and part != "auto"]
    if parts:
        return ", ".join(parts)
    compact_parts = [
        _compact_label(parsed.get(key), compact_labels)
        for key in ("shot_size", "angle", "distance")
    ]
    compact_parts = [part for part in compact_parts if part and part != "auto"]
    return ", ".join(compact_parts)


def pov_camera_geometry_phrase(parsed: dict[str, Any], compact_labels: Mapping[str, str] | None = None) -> str:
    elevation = str(parsed.get("orbit_elevation_label") or "").strip()
    distance = str(parsed.get("orbit_distance_label") or "").strip()
    custom = str(parsed.get("custom_camera_prompt") or "").strip()
    if custom:
        elevation = elevation or camera_elevation_from_text(custom)
        distance = distance or camera_distance_from_text(custom)
    parts = [part for part in (elevation, distance) if part and part != "auto"]
    if parts:
        return ", ".join(parts)
    compact_parts = [
        _compact_label(parsed.get(key), compact_labels)
        for key in ("shot_size", "distance")
    ]
    compact_parts = [part for part in compact_parts if part and part != "auto"]
    return ", ".join(compact_parts)


def camera_direction_from_text(text: Any) -> str:
    source = str(text or "").lower()
    for label in CAMERA_DIRECTIONS:
        if label in source:
            return label
    return ""


def camera_elevation_from_text(text: Any) -> str:
    source = str(text or "").lower()
    for label in CAMERA_ELEVATIONS:
        if label in source:
            return label
    return ""


def camera_distance_from_text(text: Any) -> str:
    source = str(text or "").lower()
    for label in CAMERA_DISTANCES:
        if label in source:
            return label
    return ""


def coworking_location_profile(scene_text: Any) -> dict[str, str]:
    profile = scene_camera_profile(scene_text)
    if profile.get("family") == "coworking":
        return profile
    return scene_camera_profile("coworking lounge")


def scene_subject_terms(subject_kind: str, pov_labels: list[str] | None = None) -> tuple[str, str]:
    if pov_labels:
        return "the visible partner", "them"
    if subject_kind == "woman":
        return "the woman", "her"
    if subject_kind == "man":
        return "the man", "him"
    if subject_kind == "couple":
        return "the couple", "them"
    return "the subjects", "them"


def coworking_subject_terms(subject_kind: str, pov_labels: list[str] | None = None) -> tuple[str, str]:
    return scene_subject_terms(subject_kind, pov_labels)


def scene_direction_detail(
    direction: str,
    profile: dict[str, str],
    pov_labels: list[str] | None = None,
    subject_kind: str = "subjects",
) -> str:
    direction = str(direction or "").strip().lower()
    foreground = profile["foreground"]
    midground = profile["midground"]
    background = profile["background"]
    detail_label = profile.get("detail_label") or "location details"
    subject, pronoun = scene_subject_terms(subject_kind, pov_labels)
    is_verb = "are" if subject == "the subjects" else "is"
    face_verb = "face" if subject == "the subjects" else "faces"
    if pov_labels:
        if "right side" in direction:
            return f"{subject} stays readable in the first-person action while {midground} run along the viewer's right-side background toward {background}, with {detail_label} kept at the frame edges"
        if "left side" in direction:
            return f"{subject} stays readable in the first-person action while {midground} run along the viewer's left-side background toward {background}, with {detail_label} kept at the frame edges"
        if "back-right" in direction or "back-left" in direction:
            return f"{subject} stays close in one continuous first-person action frame; {midground} lead diagonally toward {background} along the side/background edges"
        if direction == "back view":
            return f"{subject} and the action stay primary while {midground} and {background} remain beyond the body, with POV body cues sitting low in frame"
        if "front-right" in direction or "front-left" in direction:
            return f"{subject} fills the first-person action frame while {midground} recede diagonally behind {pronoun} toward {background}"
        return f"{subject} faces the viewer in first-person view; {midground} and {background} stay behind {pronoun} at background depth"
    if "right side" in direction or "left side" in direction:
        return f"{subject} {is_verb} held in side profile along the {foreground}; {midground} run laterally behind {pronoun}, with {background} still readable"
    if "back-right" in direction or "back-left" in direction:
        return f"{subject} {is_verb} viewed from a rear-quarter angle, partly turning back toward camera; the {foreground} stays low in frame while {midground} lead into {background}"
    if direction == "back view":
        return f"{subject} {is_verb} seen from behind with the {foreground} at camera side, facing into {midground} and {background}"
    if "front-right" in direction or "front-left" in direction:
        return f"{subject} {is_verb} placed beside the {foreground}; {midground} recede diagonally behind {pronoun} toward {background}"
    return f"{subject} {face_verb} camera beside the {foreground}; {midground} sit between {pronoun} and {background}"


def coworking_direction_detail(
    direction: str,
    profile: dict[str, str],
    pov_labels: list[str] | None = None,
    subject_kind: str = "subjects",
) -> str:
    return scene_direction_detail(direction, profile, pov_labels, subject_kind)


def scene_distance_detail(
    distance: str,
    profile: dict[str, str],
    subject_kind: str,
    pov_labels: list[str] | None = None,
) -> str:
    distance = str(distance or "").strip().lower()
    subject, _pronoun = scene_subject_terms(subject_kind, pov_labels)
    if pov_labels:
        if "wide" in distance or "full-body" in distance or "full body" in distance:
            return f"wide POV keeps {subject} readable with {profile['place']} context behind them and environmental anchors only beside or beyond the action"
        if "close" in distance:
            return f"close POV keeps {subject} dominant with {profile['place']} context only at the sides or background"
        return f"medium POV keeps {subject} dominant with room context beside or behind them"
    if "wide" in distance or "full-body" in distance or "full body" in distance:
        return f"wide crop keeps the {profile['foreground']}, {profile['midground']}, and {profile['background']} readable"
    if "close" in distance:
        return f"close crop keeps one anchor from the {profile['foreground']} visible"
    return f"medium crop keeps {subject} dominant"


def coworking_distance_detail(
    distance: str,
    profile: dict[str, str],
    subject_kind: str,
    pov_labels: list[str] | None = None,
) -> str:
    return scene_distance_detail(distance, profile, subject_kind, pov_labels)


def scene_elevation_detail(
    elevation: str,
    profile: dict[str, str],
    subject_kind: str,
    pov_labels: list[str] | None = None,
) -> str:
    elevation = str(elevation or "").strip().lower()
    subject, pronoun = scene_subject_terms(subject_kind, pov_labels)
    if pov_labels:
        if "low-angle" in elevation:
            return f"low angle keeps POV body cues low while the {profile['background']} rises behind {pronoun}"
        if "elevated" in elevation:
            return f"elevated POV keeps the viewer's eye line slightly higher than {subject}, with location anchors only beside or behind {pronoun}"
        if "high-angle" in elevation:
            return f"high angle looks down from the viewer's position with {profile['midground']} only in the background"
        return f"eye-level angle keeps {profile['midground']} behind {pronoun}"
    if "low-angle" in elevation:
        return f"low angle keeps the {profile['foreground']} low while {profile['background']} rises behind {pronoun}"
    if "elevated" in elevation:
        return f"elevated angle shows the {profile['foreground']} and {profile['midground']} around {pronoun}"
    if "high-angle" in elevation:
        return f"high angle shows the {profile['place']} layout and placement of {pronoun}"
    return f"eye-level angle keeps {profile['midground']} visually stable"


def coworking_elevation_detail(
    elevation: str,
    profile: dict[str, str],
    subject_kind: str,
    pov_labels: list[str] | None = None,
) -> str:
    return scene_elevation_detail(elevation, profile, subject_kind, pov_labels)


def scene_camera_directive(
    scene_text: Any,
    parsed: dict[str, Any],
    pov_labels: list[str] | None = None,
    subject_kind: str = "subjects",
    compact_labels: Mapping[str, str] | None = None,
    *,
    scene_entry: Any = None,
    theme: Any = "",
    profile_key: Any = "",
) -> str:
    profile = scene_camera_profile(scene_text, scene_entry=scene_entry, theme=theme, profile_key=profile_key)
    if not profile:
        return ""
    direction = str(parsed.get("orbit_direction") or "").strip()
    elevation = str(parsed.get("orbit_elevation_label") or "").strip()
    distance = str(parsed.get("orbit_distance_label") or "").strip()
    custom_prompt = str(parsed.get("custom_camera_prompt") or "").strip()
    direction = direction or camera_direction_from_text(custom_prompt)
    elevation = elevation or camera_elevation_from_text(custom_prompt)
    distance = distance or camera_distance_from_text(custom_prompt)
    if not any((direction, elevation, distance, custom_prompt)):
        return ""
    direction_detail = scene_direction_detail(direction, profile, pov_labels, subject_kind)
    distance_detail = scene_distance_detail(distance, profile, subject_kind, pov_labels)
    elevation_detail = scene_elevation_detail(elevation, profile, subject_kind, pov_labels)
    geometry = pov_camera_geometry_phrase(parsed, compact_labels) if pov_labels else camera_geometry_phrase(parsed, compact_labels)
    geometry_clause = f" ({geometry})" if geometry else ""
    if pov_labels:
        subject, _pronoun = scene_subject_terms(subject_kind, pov_labels)
        return (
            f"{profile['layout_label']} from POV{geometry_clause}: keep {subject} and the action primary; "
            f"{profile['place']} context stays beside or behind the bodies and along the side/background edges; "
            f"POV body or hand cues stay in the lower foreground."
        )
    return (
        f"{profile['layout_label']}{geometry_clause}: {direction_detail}; "
        f"{distance_detail}; {elevation_detail}."
    )


def coworking_camera_scene_directive(
    scene_text: Any,
    parsed: dict[str, Any],
    pov_labels: list[str] | None = None,
    subject_kind: str = "subjects",
    compact_labels: Mapping[str, str] | None = None,
) -> str:
    if not is_coworking_scene(scene_text):
        return ""
    return scene_camera_directive(scene_text, parsed, pov_labels, subject_kind, compact_labels)


def profile_composition_text(profile: dict[str, Any], subject_kind: str) -> str:
    composition = profile.get("composition") if isinstance(profile.get("composition"), dict) else {}
    if subject_kind == "woman" and composition.get("woman"):
        return str(composition["woman"])
    if subject_kind == "man" and composition.get("man"):
        return str(composition["man"])
    text = str(composition.get("default") or f"{profile['place']} frame with the subjects clearly placed in the room")
    text = composition_subject_text(text, subject_kind)
    if "composition" not in text.lower():
        text = f"{text} composition"
    return text


def composition_subject_text(text: str, subject_kind: str) -> str:
    replacements: dict[str, str] = {}
    if subject_kind == "woman":
        replacements = {"The subjects": "The woman", "the subjects": "the woman"}
    elif subject_kind == "man":
        replacements = {"The subjects": "The man", "the subjects": "the man"}
    elif subject_kind == "couple":
        replacements = {
            "The subjects": "The couple",
            "the subjects": "the couple",
            "The woman": "The couple",
            "the woman": "the couple",
            "The man": "The couple",
            "the man": "the couple",
        }
    for old, new in replacements.items():
        text = text.replace(old, new)
    return text


ACTION_COMPOSITION_TERMS = (
    "action geography",
    "anal",
    "ass",
    "body contact",
    "cowgirl",
    "doggy",
    "explicit",
    "first-person",
    "foreground hands",
    "genital",
    "hips",
    "kneeling",
    "mouth",
    "oral",
    "penetration",
    "pov",
    "rear-entry",
    "rear entry",
    "rear-view",
    "sexual contact",
)


def is_action_specific_composition(text: Any) -> bool:
    lower = str(text or "").lower()
    return any(term in lower for term in ACTION_COMPOSITION_TERMS)


def contextual_composition_prompt(
    scene_text: Any,
    composition: Any,
    subject_kind: str = "subjects",
    *,
    scene_entry: Any = None,
    theme: Any = "",
    profile_key: Any = "",
) -> str:
    text = str(composition or "").strip()
    if not text:
        return text
    if is_action_specific_composition(text):
        return text
    text = composition_subject_text(text, subject_kind)
    profile = scene_camera_profile(scene_text, scene_entry=scene_entry, theme=theme, profile_key=profile_key)
    if not profile:
        return text
    lower = text.lower()
    profile_lower = " ".join(
        str(profile.get(key, "")).lower()
        for key in ("place", "foreground", "midground", "background")
    )
    already_matches = any(term and term in lower for term in profile_lower.replace(",", " ").split())
    mismatched = any(term in lower for term in MISMATCHED_COMPOSITION_TERMS)
    office_generic = any(term in lower for term in ("office-lobby", "office lobby", "walking composition", "outfit-check"))
    if not mismatched and not office_generic and already_matches:
        return text
    if not mismatched and not office_generic and profile.get("family") != "coworking":
        return text
    return profile_composition_text(profile, subject_kind)


def coworking_composition_prompt(scene_text: Any, composition: Any, subject_kind: str = "subjects") -> str:
    return contextual_composition_prompt(scene_text, composition, subject_kind)


def camera_scene_directive_for_context(
    scene_text: Any,
    parsed_camera_config: dict[str, Any],
    pov_labels: list[str] | None = None,
    subject_kind: str = "subjects",
    compact_labels: Mapping[str, str] | None = None,
    *,
    scene_entry: Any = None,
    theme: Any = "",
    profile_key: Any = "",
) -> str:
    if (
        parsed_camera_config.get("camera_detail") == "off"
        or parsed_camera_config.get("camera_mode") == "disabled"
    ):
        return ""
    return scene_camera_directive(
        scene_text,
        parsed_camera_config,
        pov_labels,
        subject_kind,
        compact_labels,
        scene_entry=scene_entry,
        theme=theme,
        profile_key=profile_key,
    )
