# wcs/games/millionaire_prompts.py
"""
Prompt builders for Continuous Chat Millionaire.

Single module for all prompt construction: system prompt, user messages
(welcome, question, feedback). Used by MillionaireGameController.

Prompt guidelines: .agents/skills/app-prompts/SKILL.md.
"""

import xbmcaddon


# ---------------------------------------------------------------------------
# Money amounts (1-9)
# ---------------------------------------------------------------------------
MONEY_AMOUNTS = {
    1: "1 000 Kč",
    2: "2 000 Kč",
    3: "5 000 Kč",
    4: "10 000 Kč",
    5: "20 000 Kč",
    6: "50 000 Kč",
    7: "100 000 Kč",
    8: "500 000 Kč",
    9: "1 000 000 Kč",
}


def _get_difficulty_for_round(round_num):
    """Return difficulty label for a given round number (1-9)."""
    if round_num <= 3:
        return "SNADNÁ"
    elif round_num <= 6:
        return "STŘEDNÍ"
    return "TĚŽKÁ"


def _get_global_difficulty():
    """Return global difficulty header from addon settings.

    Settings: millionaire_difficulty (0=easy, 1=medium, 2=hard).
    """
    addon = xbmcaddon.Addon()
    setting = addon.getSetting("millionaire_difficulty")
    if setting == "0":
        return (
            "HLAVNÍ OBTÍŽNOST CELÉ HRY: SNADNÁ – Formuluj otázky jednoduše "
            "z obecně známých informací. Vyhýbej se detailům a insider faktům. "
            "Možnosti odpovědí musí být zřetelně odlišitelné."
        )
    elif setting == "2":
        return (
            "HLAVNÍ OBTÍŽNOST CELÉ HRY: TĚŽKÁ – Opírej otázky o hlubší "
            "znalosti a přesné kontexty. Využívej odbornější pojmy. "
            "Možnosti odpovědí musí být velmi věrohodné a pečlivě odlišitelné."
        )
    return (
        "HLAVNÍ OBTÍŽNOST CELÉ HRY: STŘEDNÍ – Pracuj s mírnou mírou "
        "detailu nad mainstream. Zachovej srozumitelnost. "
        "Možnosti odpovědí musí být věrohodné, nikoli zavádějící."
    )


# ---------------------------------------------------------------------------
# Text length settings
# ---------------------------------------------------------------------------

# Maps setting index to Czech length instruction per text type
_LENGTH_INSTRUCTIONS = {
    # Character limits: the texts are read on a TV card (the moderator's card of the answer screen holds ~4 lines of
    # ~60 characters, the intro card ~7); models keep a number far better than "short sentences".
    # welcome (moderator_welcome + rules_summary)
    "welcome": [
        "Pouze název hry, žádné uvítání.",                    # 0 = extra short
        "Jedna krátká věta, nejvýše 90 znaků.",                # 1 = short
        "Dvě krátké věty, dohromady nejvýše 170 znaků.",       # 2 = medium
        "3-4 věty, nejvýše 300 znaků.",                        # 3 = long
    ],
    "rules_summary": [
        "Pouze počet otázek.",
        "Jedna krátká věta, nejvýše 80 znaků.",
        "Jedna věta, nejvýše 110 znaků.",
        "2-3 věty, nejvýše 220 znaků.",
    ],
    # moderator_intro (spoken before the question)
    "intro": [
        "Žádný úvod, rovnou otázka. Ponech prázdné.",
        "Jedna krátká věta, nejvýše 90 znaků.",
        "1-2 krátké věty, nejvýše 150 znaků.",
        "2-3 věty, dramatické, nejvýše 250 znaků.",
    ],
    # result_announcement (shown together with transition_text on the answer screen)
    "result": [
        "Jedno slovo: Správně! nebo Špatně!",
        "Jedna krátká věta, nejvýše 70 znaků.",
        "1-2 krátké věty, dohromady nejvýše 110 znaků.",
        "2-3 věty, nejvýše 200 znaků.",
    ],
    # transition_text
    "transition": [
        "Žádný přechod. Ponech prázdné.",
        "Jedna krátká věta, nejvýše 60 znaků.",
        "1-2 krátké věty, nejvýše 100 znaků.",
        "2 věty, nejvýše 160 znaků.",
    ],
    # explanation (2 lines of ~70 characters under the right answer)
    "explanation": [
        "Žádné vysvětlení. Ponech prázdné.",
        "Jedna věta, nejvýše 130 znaků.",
        "1-2 věty, nejvýše 200 znaků.",
        "2-3 věty, edukativní, nejvýše 300 znaků.",
    ],
}


def _load_text_lengths():
    """Load text length settings from addon. Returns dict of instructions."""
    import xbmcaddon
    addon = xbmcaddon.Addon()
    settings = {
        "welcome": addon.getSetting("milionar_len_welcome") or "2",
        "intro": addon.getSetting("milionar_len_intro") or "1",
        "result": addon.getSetting("milionar_len_result") or "2",
        "transition": addon.getSetting("milionar_len_transition") or "1",
        "explanation": addon.getSetting("milionar_len_explanation") or "1",
    }
    result = {}
    for key, raw in settings.items():
        try:
            idx = int(raw)
        except ValueError:
            idx = 1  # default to short
        instructions = _LENGTH_INSTRUCTIONS.get(key, ["1 věta."] * 4)
        result[key] = instructions[min(idx, len(instructions) - 1)]
    # rules_summary follows welcome setting
    welcome_idx = int(settings.get("welcome", "2"))
    rules_instr = _LENGTH_INSTRUCTIONS["rules_summary"]
    result["rules_summary"] = rules_instr[min(welcome_idx, len(rules_instr) - 1)]
    return result


# ---------------------------------------------------------------------------
# Media context builders
# ---------------------------------------------------------------------------

def _build_media_context(media_type, title, plot="", genre="",
                         episode_title="", season_number=None,
                         episode_number=None, actor_data=None):
    """Build media context block for system prompt.

    Returns a multi-line string with subject identification, plot/bio,
    genre, and known roles.
    """
    lines = []

    if media_type in ("actor", "director", "writer", "creator"):
        data = actor_data or {}
        name = data.get("name", title)
        bio = data.get("biography", "")
        known_for = data.get("known_for", [])
        role_labels = {
            "actor": "herci",
            "director": "režisérovi",
            "writer": "scénáristovi",
            "creator": "tvůrci seriálů",
        }
        lines.append("PŘEDMĚT KVÍZU: {} {}".format(
            role_labels.get(media_type, "osobnosti"), name
        ))
        if bio:
            lines.append("ŽIVOTOPIS: {}".format(bio[:600]))
        if known_for:
            titles = [
                item.get("title") or item.get("name", "")
                for item in known_for[:10]
            ]
            lines.append("ZNÁMÁ DÍLA: {}".format(", ".join(titles)))
    else:
        # movie / series / channel
        if media_type == "channel":
            subj = 'kanál "{}" (mix více seriálů)'.format(title)
            lines.append("PŘEDMĚT KVÍZU: {}".format(subj))
            if plot:
                lines.append("SERIÁLY V KANÁLU:\n{}".format(plot[:2000]))
            lines.append(
                "INSTRUKCE: Otázky generuj STŘÍDAVĚ a NÁHODNĚ ze všech "
                "seriálů v kanálu. Každá otázka by měla být z jiného seriálu "
                "než předchozí (pokud je to možné). V moderator_intro vždy "
                "uveď, ze kterého seriálu je aktuální otázka."
            )
        elif media_type == "series":
            if episode_title:
                subj = 'seriál "{}", epizoda "{}"'.format(title, episode_title)
                if season_number and episode_number:
                    subj += " (S{:02d}E{:02d})".format(
                        season_number, episode_number
                    )
            else:
                subj = 'seriál "{}"'.format(title)
            lines.append("PŘEDMĚT KVÍZU: {}".format(subj))
            if plot:
                lines.append("DĚJ: {}".format(plot[:600]))
            if genre:
                lines.append("ŽÁNR: {}".format(genre))
        else:
            subj = 'film "{}"'.format(title)
            lines.append("PŘEDMĚT KVÍZU: {}".format(subj))
            if plot:
                lines.append("DĚJ: {}".format(plot[:600]))
            if genre:
                lines.append("ŽÁNR: {}".format(genre))

    return "\n".join(lines)


# ---------------------------------------------------------------------------
# SYSTEM PROMPT
# ---------------------------------------------------------------------------

def build_system_prompt(media_type, title, plot="", genre="",
                        episode_title="", season_number=None,
                        episode_number=None, actor_data=None):
    """Build the fixed system prompt for an entire Millionaire game session.

    Structure:
    Role -> Context -> Style (from SKILL.md) -> Task -> Format -> Constraints
    """
    global_difficulty = _get_global_difficulty()
    media_context = _build_media_context(
        media_type, title, plot, genre,
        episode_title, season_number, episode_number, actor_data
    )

    # Load moderator style from SKILL.md (runtime)
    from wcs.games.moderator_styles import get_style_prompt_block
    style_block = get_style_prompt_block()

    # Load text length preferences
    lengths = _load_text_lengths()

    # ElevenLabs v3 audio tags injection
    from wcs.games.millionaire_tts import is_elevenlabs_v3_active
    audio_tags_block = ""
    if is_elevenlabs_v3_active():
        audio_tags_block = """

AUDIO TAGY:
Text je čten nahlas expresivním TTS modelem. Do textových polí (moderator_welcome, rules_summary, moderator_intro, result_announcement, transition_text, explanation) vkládej audio tagy v [hranatých závorkách] -- řídí emoce a tempo hlasu.

Dostupné tagy:
- Emoce: [excited] [nervous] [frustrated] [sorrowful] [calm] [sad] [angry] [happily] [tired] [curious] [mischievously]
- Reakce: [sigh] [sighs] [laughs] [laughing] [gasps] [gulps] [whispers] [clears throat] [exhales] [panting] [hesitates] [stammers] [pauses]
- Tón: [cheerfully] [flatly] [deadpan] [playfully] [dramatically] [sarcastically] [matter-of-fact] [whispering] [shouting] [quietly] [loudly] [rushed]
- Zvuky: [clapping] [explosion] [door creaks]

Pravidla:
- Každý text musí mít minimálně 2-3 tagy
- Vkládej přirozeně DO textu, ne na začátek
- Kombinuj emoce + reakce + pacing
- Stupňuj expresivitu s rostoucí částkou
- U správné odpovědi: [excited], [laughs], [cheerfully], [clapping]
- U špatné odpovědi: [sighs], [sorrowful], [pauses], [quietly]
- U napínavých momentů: [dramatically], [pauses], [whispers], [gasps]
- NEpoužívej tagy v poli "question" a "options" -- tam patří čistý text

Příklad moderator_intro: "[dramatically] Tak tady jsme, [pauses] otázka za padesát tisíc! [excited] Jste připraveni?"
Příklad result_announcement: "[gasps] [excited] A je to správně! [clapping] [cheerfully] Výborně, postupujete dál!"
"""

    prompt = """\
ROLE:
Jsi moderátor českého kvízu "Chcete být milionářem". Znáš dílo, o kterém se hraje, a odkazuješ na něj v komentářích. Hráče oslovuješ vykáním.

STYL MODERÁTORA:
{style_block}

{global_difficulty}

KONTEXT:
{media_context}
{audio_tags_block}
HERNÍ STRUKTURA:
- 9 kol, 3 úrovně obtížnosti; každé kolo je těžší než předchozí
- Kola 1-3: SNADNÁ – odpoví každý, kdo dílo viděl: hlavní postavy a jejich představitelé, základní zápletka, nejslavnější momenty
- Kola 4-6: STŘEDNÍ – pro pozorného diváka: vedlejší postavy, konkrétní scény, jména míst a předmětů, motivace postav
- Kola 7-9: TĚŽKÁ – pro skutečného fanouška: drobné detaily konkrétních scén, citáty, souvislosti mezi událostmi, méně známí herci a tvůrci; zákulisí jen tam, kde je fakt všeobecně doložený
- Částky: 1 000 / 2 000 / 5 000 / 10 000 / 20 000 / 50 000 / 100 000 / 500 000 / 1 000 000 Kč
- 3 nápovědy: 50:50, Tip, Hlasování diváků

ÚKOL:
Vedeš celou hru jako continuous chat. V každém kole dostaneš instrukci, jaký typ odpovědi máš vrátit (welcome / otázka / feedback). Vždy odpovídáš POUZE validním JSON objektem.

TŘI TYPY ODPOVĚDÍ:

1. WELCOME (úvodní zpráva):
{{"moderator_welcome": "Přivítání hráče u kvízu o tomto díle: osobní myšlenka k dílu nebo jeho atmosféře, která naladí na hru. Neprozrazuj děj ani odpovědi. {len_welcome}", "rules_summary": "Pravidla: 9 otázek od snadných po těžké, 3 nápovědy, cílem je virtuální milion. {len_rules}"}}
Úvod hráč čte na obrazovce s názvem díla, počtem otázek a nápověd: drž ho krátký a nezačínej pokaždé stejnou formulí.

2. QUESTION (otázka pro hráče):
{{"moderator_intro": "Úvod ke kolu. Zmíň číslo kola, částku, vytvoř napětí, odkaž na kontext díla. {len_intro}", "explanation": "Fakt z díla, na kterém otázka stojí, a proč je správná odpověď správná. {len_explanation}", "question": "Text otázky", "options": {{"A": "Možnost A", "B": "Možnost B", "C": "Možnost C", "D": "Možnost D"}}, "correct": "A"}}
Pole "explanation" piš před otázkou: nejdřív si zvol fakt, který znáš jistě, a otázku postav až na něm. Hráč vysvětlení uvidí až po odpovědi.

3. FEEDBACK (výsledek odpovědi):
{{"result_announcement": "Reakce moderátora na odpověď: řekni, zda je správná, a přidej jeden vtipný nebo zajímavý postřeh k dílu nebo k tématu otázky. {len_result}", "transition_text": "Naladění na další kolo -- u přechodu obtížnosti ho zmiň; po špatné odpovědi nebo milionu rozloučení. {len_transition}"}}
Hráč má před sebou na obrazovce velký nápis Správně/Špatně, správnou odpověď, vysvětlení, získanou částku i částku další otázky: ve feedbacku je neopakuj, přidej to, co tam není (milion v posledním kole zmínit můžeš). Začátek obměňuj, nezačínej pokaždé slovem "Správně".

PRAVIDLA OTÁZEK:
- Každá otázka má přesně 4 možnosti (A, B, C, D)
- Správná odpověď jako jedno písmeno (A, B, C nebo D)
- Každá možnost odpovědi má nejvýše 25 znaků včetně mezer: heslovitě (jméno, slovo nebo krátké spojení), ne věta -- delší text se na tlačítko nevejde
- Neopakuj otázky -- máš celou historii chatu, využij ji
- Obtížnost otázky odpovídá aktuálnímu kolu (vidíš v user message); hlavní postavy a představitelé hlavních rolí patří do snadných kol
- Ptej se jen na fakta, která znáš jistě. Když si fakt nejsi jistý, vyber jinou otázku -- chybnou správnou odpověď hráč pozná a hra ztratí důvěryhodnost.
- Pravdivé musí být celé zadání, nejen správná odpověď: každá postava, role, místo a okolnost, kterou otázka zmiňuje, odpovídá dílu.
- Nevymýšlej jména, přezdívky ani čísla, která si přesně nepamatuješ; na jméno postavy, která ho v díle nemá, se neptej.
- Otázka se ptá na jednu věc, kterou sama neuvádí; správná odpověď ani její část (jméno, číslo) nezazní v textu otázky. Má jedinou jednoznačně správnou odpověď.
- Jména postav, míst a předmětů piš tak, jak je zná český divák z dabingu nebo překladu; když český název jistě neznáš, použij originální.
- Špatné možnosti jsou skutečné věci stejného druhu jako správná odpověď (jména se jmény, roky s roky), nejlépe z téhož díla; žádná není jiný název, překlad nebo zkrácení správné odpovědi a žádná není vymyšlený nesmysl.
- Obtížnost dělá to, na co se ptáš, a věrohodné špatné možnosti, ne zavádějící formulace.
- Každá otázka hry se týká jiného faktu a má jinou správnou odpověď než předchozí.
- Hráč vidí jen text: otázka musí dávat smysl bez obrázku a bez odkazu na "tuto scénu" nebo "tento záběr".
- Nepoužívej otázky typu "Která z těchto možností je správná?" -- formuluj konkrétně

PRAVIDLA MODERÁTORA:
- Dodržuj styl definovaný výše v sekci STYL MODERÁTORA
- Stupňuj napětí s rostoucí obtížností a částkou
- Reaguj na kontext -- pokud hráč odpovídá správně, pochval; pokud špatně, projev soucit
- Odkazuj na dílo přirozeně, ne nuceně
- U přechodu obtížnosti (kolo 3->4, 6->7) zmíň zvýšení obtížnosti
- U posledního kola (9) zdůrazni, že jde o milion
- Mluv česky, přirozeně, ne roboticky
- Pohlaví hráče neznáš: vykej v množném čísle (zvládli jste), nikdy nepiš tvary typu "trefil(a)"
- U vážných a tragických děl (katastrofy, válka, smrt) tlum humor: vtipkuj o sobě nebo o hře, nikdy o obětech a utrpení
- Nepočítej odehraná kola a neopakuj obraty z předchozích kol -- každá reakce je nová
- Limity znaků u jednotlivých polí dodrž: texty se čtou na televizní obrazovce a delší se nevejdou

VÝSTUP:
Odpověď je jeden validní JSON objekt bez textu okolo a bez markdown bloku -- aplikace ho strojově parsuje.""".format(
        style_block=style_block,
        global_difficulty=global_difficulty,
        media_context=media_context,
        audio_tags_block=audio_tags_block,
        len_welcome=lengths["welcome"],
        len_rules=lengths["rules_summary"],
        len_intro=lengths["intro"],
        len_result=lengths["result"],
        len_transition=lengths["transition"],
        len_explanation=lengths["explanation"],
    )

    return prompt


# ---------------------------------------------------------------------------
# USER MESSAGES
# ---------------------------------------------------------------------------

def build_welcome_message():
    """Build user message for the welcome inference (inference 1)."""
    lengths = _load_text_lengths()
    return (
        "Začni hru. Přivítej hráče, představ téma kvízu a stručně vysvětli "
        "pravidla. Odpověz typem WELCOME."
    ) + _length_note(("moderator_welcome", lengths["welcome"]), ("rules_summary", lengths["rules_summary"]))


# Angles of the questions about a film / series. Each game draws its own order (AiContent), so a replayed title does
# not bring the same questions again; the model may leave an angle when it knows no sure fact for it.
QUESTION_ANGLES = (
    "co konkrétní postava udělá nebo řekne v určité scéně",
    "místo, kde se něco odehrává",
    "předmět nebo rekvizita důležitá pro děj",
    "známá hláška nebo citát",
    "vztah mezi dvěma postavami",
    "vedlejší postava",
    "začátek děje",
    "zlom nebo vyvrcholení děje",
    "jméno, přezdívka nebo povolání postavy",
    "hudba nebo píseň v díle",
    "herec nebo herečka v roli",
    "číslo, datum nebo částka z děje",
    "zvíře nebo dopravní prostředek v díle",
    "dopis, dárek nebo vzkaz v ději",
)
ANGLE_MEDIA = ("movie", "series", "channel")


def build_question_message(round_num, angle=None):
    """Build user message requesting a new question (inference 2, 4, 6, ...).

    Args:
        round_num: Current round number (1-9).
        angle: Optional angle of the question (QUESTION_ANGLES), drawn per game for variety.
    """
    difficulty = _get_difficulty_for_round(round_num)
    money = MONEY_AMOUNTS.get(round_num, "1 000 Kč")

    # Level transition notes
    transition_note = ""
    if round_num == 4:
        transition_note = " Přecházíme na STŘEDNÍ obtížnost."
    elif round_num == 7:
        transition_note = " Přecházíme na TĚŽKOU obtížnost."
    elif round_num == 9:
        transition_note = " Toto je POSLEDNÍ otázka za MILION!"

    # The tier reminder sits next to the request: in a long chat the model otherwise drifts back to easy questions
    audience = {
        "SNADNÁ": "Otázka pro každého, kdo dílo viděl.",
        "STŘEDNÍ": "Otázka pro pozorného diváka, těžší než v předchozím kole.",
        "TĚŽKÁ": "Otázka pro skutečného fanouška, těžší než v předchozím kole -- ne na hlavní postavy ani jejich představitele.",
    }[difficulty]

    angle_note = (" Úhel otázky: {}. Když k němu neznáš jistý fakt v této obtížnosti, zvol jiný úhel.".format(angle)
                  if angle else "")

    lengths = _load_text_lengths()
    return (
        "Kolo {round_num}/9, obtížnost: {difficulty}, částka: {money}."
        "{transition_note} {audience}{angle_note} Vygeneruj otázku. Odpověz typem QUESTION."
    ).format(
        round_num=round_num,
        difficulty=difficulty,
        money=money,
        transition_note=transition_note,
        audience=audience,
        angle_note=angle_note,
    ) + _length_note(("moderator_intro", lengths["intro"]), ("explanation", lengths["explanation"]))


def build_feedback_message(round_num, player_answer_letter, player_answer_text,
                           correct_answer_letter, correct_answer_text,
                           is_correct, is_last_round=False):
    """Build user message requesting feedback after player's answer.

    Args:
        round_num: Current round number (1-9).
        player_answer_letter: Letter chosen by player (A/B/C/D).
        player_answer_text: Text of the chosen answer.
        correct_answer_letter: Correct answer letter.
        correct_answer_text: Text of the correct answer.
        is_correct: Whether the player answered correctly.
        is_last_round: Whether this is round 9.
    """
    result = "SPRÁVNĚ" if is_correct else "ŠPATNĚ"

    # Amounts and round numbers are on the screen; the message carries only what the moderator needs to react to
    # (models otherwise repeat "kolo 6 za 50 000 Kč" in every transition).
    msg = (
        "Kolo {round_num}/9. Hráč vybral {player_letter}: {player_text}. "
        "Správná odpověď: {correct_letter}: {correct_text}. "
        "Hráč odpověděl {result}."
    ).format(
        round_num=round_num,
        player_letter=player_answer_letter,
        player_text=player_answer_text,
        correct_letter=correct_answer_letter,
        correct_text=correct_answer_text,
        result=result,
    )

    if is_correct and is_last_round:
        msg += " Hráč vyhrál MILION! Gratuluj a rozluč se."
    elif is_correct:
        msg += {4: " Další kolo začíná STŘEDNÍ obtížností.", 7: " Další kolo začíná TĚŽKOU obtížností.",
                9: " Další otázka je o milion."}.get(round_num + 1, "")
    else:
        msg += " Konec hry. Rozluč se s hráčem."
    msg += " Odpověz typem FEEDBACK."

    lengths = _load_text_lengths()
    return msg + _length_note(("result_announcement", lengths["result"]), ("transition_text", lengths["transition"]))


def _length_note(*fields):
    """The length limits repeated next to the request: in a long chat the system prompt is far away and models drift
    to longer texts (texts are read on a TV card)."""
    return " Délky: " + "; ".join("{} -- {}".format(name, rule.rstrip(".")) for name, rule in fields) + "."
