from __future__ import annotations from typing import Any from fupogfakta.models import GameSession, RoundQuestion from lobby.i18n import i18n_locale_config from .models import PhaseVoiceLine, QuestionVoiceLine VOICE_GAME_KEY = "fupogfakta" DEFAULT_PHASE_LINES: dict[str, dict[str, str]] = { "en": { "intro": ( "Welcome to Fup og Fakta. Invent a believable lie, spot the real answer, " "and score points when other players believe your bluff." ), "lobby": "Players are joining the session. Get ready to start the round.", "lie": "The question is live. Players, write one believable lie before time runs out.", "guess": "The answers are mixed. Pick the answer you believe is true.", "reveal": "Time to reveal the lies, the guesses, and the correct answer.", "scoreboard": "Here comes the scoreboard for this round.", "finished": "The game is finished. Here is the final result.", }, "da": { "intro": ( "Velkommen til Fup og Fakta. Find på en troværdig løgn, gennemsku det rigtige svar, " "og få point når andre hopper på dit bluff." ), "lobby": "Spillerne er ved at joine sessionen. Gør klar til at starte runden.", "lie": "Spørgsmålet er live. Spillere, skriv en troværdig løgn før tiden løber ud.", "guess": "Svarene er blandet. Vælg det svar du tror er rigtigt.", "reveal": "Nu afslører vi løgnene, gættene og det rigtige svar.", "scoreboard": "Her kommer scoreboardet for denne runde.", "finished": "Spillet er slut. Her er det endelige resultat.", }, } def _default_question_prompt(locale: str, prompt: str) -> str: if locale == "da": return f"Spørgsmålet lyder: {prompt}" return f"The question is: {prompt}" def _default_question_reveal(locale: str, correct_answer: str) -> str: if locale == "da": return f"Det rigtige svar er: {correct_answer}" return f"The correct answer is: {correct_answer}" def _supported_locales() -> tuple[str, tuple[str, ...]]: return i18n_locale_config() def _default_phase_line(cue_key: str, locale: str) -> str: default_locale, _locales = _supported_locales() localized_lines = DEFAULT_PHASE_LINES.get(locale) or DEFAULT_PHASE_LINES.get(default_locale) or {} return localized_lines.get(cue_key, cue_key) def _resolve_audio_url(audio_field: Any) -> str | None: if not audio_field: return None try: return str(audio_field.url) except ValueError: return None def _resolve_phase_content(*, cue_key: str, locale: str) -> tuple[str, str | None, str]: custom = ( PhaseVoiceLine.objects.filter( game_key=VOICE_GAME_KEY, cue_key=cue_key, locale=locale, is_active=True, ) .first() ) if custom: return custom.text, _resolve_audio_url(custom.audio_file), "custom" return _default_phase_line(cue_key, locale), None, "default" def _resolve_question_content( *, cue_key: str, locale: str, round_question: RoundQuestion, ) -> tuple[str, str | None, str]: custom = ( QuestionVoiceLine.objects.filter( question=round_question.question, cue_key=cue_key, locale=locale, is_active=True, ) .first() ) if custom: return custom.text, _resolve_audio_url(custom.audio_file), "custom" if cue_key == QuestionVoiceLine.CueKey.QUESTION_REVEAL: return _default_question_reveal(locale, round_question.correct_answer), None, "default" return _default_question_prompt(locale, round_question.question.prompt), None, "default" def _build_cue_payload( *, cue_key: str, text_by_locale: dict[str, str], audio_urls: dict[str, str], source: str, ) -> dict[str, Any]: return { "cue": cue_key, "translations": text_by_locale, "audio_urls": audio_urls, "source": source, } def resolve_session_voice_cues( session: GameSession, *, current_round_question: RoundQuestion | None, ) -> dict[str, Any]: default_locale, supported_locales = _supported_locales() def collect_phase(cue_key: str) -> dict[str, Any]: translations: dict[str, str] = {} audio_urls: dict[str, str] = {} source = "default" for locale in supported_locales: text, audio_url, line_source = _resolve_phase_content(cue_key=cue_key, locale=locale) translations[locale] = text if audio_url: audio_urls[locale] = audio_url if line_source == "custom": source = "custom" return _build_cue_payload( cue_key=cue_key, text_by_locale=translations, audio_urls=audio_urls, source=source, ) def collect_question(cue_key: str) -> dict[str, Any] | None: if current_round_question is None: return None translations: dict[str, str] = {} audio_urls: dict[str, str] = {} source = "default" for locale in supported_locales: text, audio_url, line_source = _resolve_question_content( cue_key=cue_key, locale=locale, round_question=current_round_question, ) translations[locale] = text if audio_url: audio_urls[locale] = audio_url if line_source == "custom": source = "custom" return _build_cue_payload( cue_key=cue_key, text_by_locale=translations, audio_urls=audio_urls, source=source, ) phase_cue_key = session.status if session.status in { GameSession.Status.LOBBY, GameSession.Status.LIE, GameSession.Status.GUESS, GameSession.Status.REVEAL, GameSession.Status.SCOREBOARD, GameSession.Status.FINISHED, } else GameSession.Status.LOBBY return { "default_locale": default_locale, "intro": collect_phase(PhaseVoiceLine.CueKey.INTRO), "phase": collect_phase(phase_cue_key), "question_prompt": collect_question(QuestionVoiceLine.CueKey.QUESTION_PROMPT) if session.status in {GameSession.Status.LIE, GameSession.Status.GUESS} else None, "question_reveal": collect_question(QuestionVoiceLine.CueKey.QUESTION_REVEAL) if session.status in {GameSession.Status.REVEAL, GameSession.Status.SCOREBOARD, GameSession.Status.FINISHED} else None, }