"""
Mapping from Romance.io JSON tag slugs to the human-readable display names shown in the UI.

The Romance.io JSON API returns tags as URL-style slugs (e.g. "from hate to love"),
while the website displays friendlier names (e.g. "enemies to lovers").
This module centralises that mapping so both plugins use the same conversion logic.
"""

from typing import List

# Mapping from JSON API tag slugs to UI/display names.
# To update: python update_tag_mappings.py
# Last tag mapping update: 2026-03-29
JSON_TO_UI_TAG_MAP = {
    "100-plus-years-fmc": "100+ years old fmc",
    "100-plus-years-mmc": "100+ years old mmc",
    "100-plus-years-nbi-mc": "100+ years old nbi-mc",
    "60-100-years-fmc": "60 - 100 years old fmc",
    "60-100-years-mmc": "60 - 100 years old mmc",
    "60-100-years-nbi-mc": "60 - 100 years old nbi-mc",
    "abuse-mc": "abuse between mcs",
    "abuse-non-mc": "third party abuse",
    "actors": "actor hero",
    "afab": "afab mc",
    "age difference": "age gap",
    "agender": "agender mc",
    "amab": "amab mc",
    "animal-abuse": "animal abuse",
    "animal-death": "animal death",
    "aristocratic heroine": "aristo/royal heroine",
    "arranged marriage": "arranged/forced marriage",
    "asexual-hero": "asexual hero",
    "asexual-heroine": "asexual heroine",
    "asexual-nbi-mc": "asexual nbi-mc",
    "athlete-nbi-mc": "athlete nbi-mc",
    "athletes": "athlete hero",
    "behind-doors": "behind closed doors",
    "bff-parent": "best friend's parent",
    "bikers": "biker hero",
    "birth-control-non-con": "birth-control non-consent",
    "bisexual": "bisexuality",
    "black-mc": "black mc",
    "body-betrayal": "body betrayal",
    "bodyguard-hero": "bodyguard/protector hero",
    "bodyguard-heroine": "bodyguard/protector heroine",
    "bodyguard-nbi-mc": "bodyguard/protector nbi-mc",
    "boss & employee": "boss & employee",
    "british-isles": "british isles",
    "bwwm": "bw/wm",
    "career professional": "white collar heroine",
    "career-professional-nbi-mc": "white collar nbi-mc",
    "central-asia": "central asia",
    "cheerful heroine": "cheerful/happy heroine",
    "child-death": "child death",
    "child-sexual-abuse": "child sexual abuse",
    "childfree-couple": "childfree",
    "chubby-nbi-mc": "chubby nbi-mc",
    "cold hero": "grumpy/cold hero",
    "cold heroine": "grumpy/ice queen",
    "cold-nbi-mc": "grumpy/cold nbi-mc",
    "commander": "warlord/commander hero",
    "consensual-non-con": "consensual non-consent",
    "cowboys": "cowboy hero",
    "creative-anatomy": "creative anatomy",
    "cruel hero": "cruel hero/bully",
    "cruel-nbi-mc": "cruel mean nbi-mc",
    "curvy-hero": "dad-bod hero",
    "daddy-kink": "daddy kink",
    "dap": "double anal",
    "dark": "dark romance",
    "death": "death / grief",
    "demi-sexual-hero": "demisexual hero",
    "demi-sexual-heroine": "demisexual heroine",
    "demi-sexual-nbi-mc": "demisexual nbi-mc",
    "disabilities and marks": "disabilities & scars",
    "double-penetration": "double penetration",
    "drug-abuse": "drug abuse",
    "dual-pov": "dual pov",
    "dub-con": "dubious consent",
    "dvp": "double vaginal",
    "early-20s-fmc": "early 20s fmc",
    "early-20s-mmc": "early 20s mmc",
    "early-20s-nbi-mc": "early 20s nbi-mc",
    "east-asia": "east asia",
    "east-asian-mc": "east asian mc",
    "east-europe": "eastern europe",
    "eastern-africa": "eastern africa",
    "eating disorder": "eating disorders",
    "explicit-open-door": "explicit open door",
    "explicit-plentiful": "explicit and plentiful",
    "f-f": "lesbian romance",
    "f-f-f": "fff+",
    "famous-nbi-mc": "famous nbi-mc",
    "fated-mates": "fated mates",
    "female-rake": "female rake",
    "fighters": "fighter hero",
    "first-person-pov": "first person pov",
    "forced-pregnancy": "forced pregnancy",
    "found-family": "found family",
    "friends-benefits": "friends with benefits",
    "from hate to love": "enemies to lovers",
    "genderfluid": "genderfluid mc",
    "gifted heroine": "gifted/super-heroine",
    "glimpses-kisses": "glimpses and kisses",
    "graphic-violence": "graphic violence",
    "grovel": "good grovel",
    "grumpy sunshine": "grumpy & sunshine",
    "harems": "harem",
    "height-difference": "height difference",
    "heroine athlete": "athlete heroine",
    "heroine sleuth": "sleuth heroine",
    "high-school": "high school",
    "highlander": "highlander hero",
    "historical western": "western frontier",
    "human-trafficking": "human trafficking",
    "humor": "funny",
    "hurt-comfort": "hurt/comfort",
    "ic-standalone": "interconnected standalone",
    "ice-skating": "ice/figure skating",
    "immortal-hero": "immortal hero",
    "immortal-heroine": "immortal heroine",
    "immortal-nbi-mc": "immortal nbi-mc",
    "in-her-30s": "in her 30s",
    "in-her-40s-50s": "in her 40s/50s",
    "in-his-30s": "in his 30s",
    "in-his-40s-50s": "in his 40s/50s",
    "in-their-30s": "in their 30s",
    "in-their-40s-50s": "in their 40s/50s",
    "indigenous-mc": "indigenous mc",
    "late-20s-fmc": "late 20s fmc",
    "late-20s-mmc": "late 20s mmc",
    "late-20s-nbi-mc": "late 20s nbi-mc",
    "latinx-mc": "latinx mc",
    "length-epic": "Epic: 600+",
    "length-long": "Long: 400-599",
    "length-medium": "Medium: 250-399",
    "length-novella": "Novella: 1-149",
    "length-short": "Short: 150-249",
    "lgbtqia hate": "queerphobia",
    "m-f": "m-f romance",
    "m-f-f": "mff",
    "m-f-m": "mfm",
    "m-f-x": "non-binary romance",
    "m-m": "gay romance",
    "m-m-f": "mmf",
    "m-m-m": "mmm+",
    "male-pov": "male pov",
    "mature couple": "older/mature",
    "mental-trauma": "mental trauma",
    "middle-africa": "middle africa",
    "miscarriage": "miscarriage / infertility",
    "mma-boxing": "fighting/mma/boxing",
    "muscular-nbi-mc": "muscular nbi-mc",
    "nerdy-hero": "nerdy hero",
    "nerdy-nbi-mc": "nerdy nbi-mc",
    "neurodivergent": "neurodivergent mc",
    "new-york-state": "new york state",
    "non-hea": "no hea",
    "non-human-hero": "non-human hero",
    "non-human-heroine": "non-human heroine",
    "non-human-nbi-mc": "non-human nbi-mc",
    "non-trad-hea": "nontraditional hea",
    "north-america": "north america",
    "northern-africa": "northern africa",
    "office": "workplace/office",
    "open-door": "open door",
    "other-man-woman": "other man/woman",
    "outlaw-heroine": "criminal heroine",
    "outlaw-nbi-mc": "criminal nbi-mc",
    "parents-bff": "parent's best friend",
    "past-abuse": "past abuse",
    "past-child-abuse": "past child abuse",
    "past-child-neglect": "past child neglect",
    "past-sexual-abuse": "past sexual abuse",
    "pirates": "pirate hero",
    "political-intrigue": "political/court intrigue",
    "politician": "politician hero",
    "poly": "poly (3+ people)",
    "poor-nbi-mc": "poor nbi-mc",
    "possessive-nbi-mc": "possessive nbi-mc",
    "praise-kink": "praise kink",
    "primal-play": "primal/chase play",
    "queer": "queer romance",
    "queer-awakening": "queer awakening",
    "rake-nbi-mc": "rakish nbi-mc",
    "rape-mc": "non-consent between mcs",
    "rape-non-mc": "third party sexual assault",
    "religious-trauma": "religious trauma",
    "rich-nbi-mc": "rich nbi-mc",
    "rockstars": "rockstar hero",
    "royal-nbi-mc": "aristo/royal nbi-mc",
    "royalty": "royal hero",
    "secret-relationship": "secret relationship",
    "sheiks": "sheik",
    "short-king": "short king",
    "short-nbi-mc": "short nbi-mc",
    "shy-hero": "shy hero",
    "shy-nbi-mc": "shy nbi-mc",
    "siblings-bff": "sibling's best friend",
    "silver-fox": "silver fox",
    "single-father": "single father",
    "single-mother": "single mother",
    "single-parent-nbi-mc": "single parent nbi-mc",
    "slim-nbi-mc": "slim nbi-mc",
    "slut-shaming": "slut shaming",
    "south asian": "south asian/desi",
    "south-america": "south america",
    "south-asia": "south asia",
    "south-east-europe": "south-east europe",
    "south-europe": "southern europe",
    "southeast-asia": "southeast asia",
    "southeast-asian-mc": "southeast asian mc",
    "southern-africa": "southern africa",
    "stepsibling": "step siblings",
    "strong heroine": "take-charge heroine",
    "suicide": "suicide / ideation",
    "sunny hero": "sunny/happy hero",
    "sunny-nbi-mc": "sunny/happy nbi-mc",
    "super rich hero": "rich hero",
    "sweet hero": "sweet/gentle hero",
    "sweet heroine": "sweet/gentle heroine",
    "sweet-hero": "sweet/gentle hero",
    "sweet-heroine": "sweet/gentle heroine",
    "sweet-nbi-mc": "sweet/gentle nbi-mc",
    "switch": "role switching",
    "tall-heroine": "tall heroine",
    "tall-nbi-mc": "tall nbi-mc",
    "teacher-hero": "teacher/coach hero",
    "teacher-heroine": "teacher/coach heroine",
    "teacher-nbi-mc": "teacher/coach nbi-mc",
    "teenage-fmc": "teenage fmc",
    "teenage-mmc": "teenage mmc",
    "teenage-nbi-mc": "teenage nbi-mc",
    "terminal-illness": "terminal illness",
    "third-person-pov": "third person pov",
    "torture-mcs": "torture of mcs",
    "torture-scs": "torture of side characters",
    "tortured-nbi-mc": "tortured nbi-mc",
    "trans-hero": "trans hero",
    "trans-heroine": "trans heroine",
    "transfemme": "transfemme mc",
    "transmasc": "transmasc mc",
    "tudors": "tudors & stuarts",
    "tycoon": "ceo/tycoon hero",
    "united-kingdom": "united kingdom",
    "victim-blaming": "victim blaming",
    "vikings": "viking hero",
    "virgin-nbi-mc": "virgin nbi-mc",
    "warrior-heroine": "warrior heroine",
    "warrior-nbi-mc": "warrior nbi-mc",
    "west-asia": "western asia",
    "west-virginia": "west virginia",
    "western-africa": "western africa",
    "western-central-europe": "western & central europe",
    "working-class-nbi-mc": "working class nbi-mc",
}

# Tags present in the JSON that have no corresponding UI display entry.
# These are filtered out rather than passed through unchanged.
TAGS_TO_IGNORE = {
    "anthologies",
    "behind-doors",
    "clean",
    "erotica",
    "explicit-open-door",
    "explicit-plentiful",
    "first-in-series",
    "glimpses-kisses",
    "legends & fairy tales",
    "length-epic",
    "length-long",
    "length-medium",
    "length-novella",
    "length-short",
    "open-door",
    "standalone-first",
}


def convert_json_tags_to_display_names(tags: List[str]) -> List[str]:
    """Convert Romance.io JSON tag slugs to the display names shown in the UI.

    Filters out entries in TAGS_TO_IGNORE and maps known slugs via JSON_TO_UI_TAG_MAP.
    Any slug not present in the map is kept as-is.

    Args:
        tags: List of raw slug strings from the JSON 'tropes' field.

    Returns:
        List of human-readable display name strings.
    """
    result = []
    for tag in tags:
        if tag in TAGS_TO_IGNORE:
            continue
        result.append(JSON_TO_UI_TAG_MAP.get(tag, tag))
    return result
