# -*- coding: utf-8 -*-
"""What a game design shows: the window properties `WCS.Game.*` derived from the state of the game controller.

`view(game)` is pure (no Kodi): it turns the controller (MillionaireGameController) into the properties of the
current screen, so a design (an XML file) only decides how they look. One screen is active at a time:

    title      welcome of the game: the work, its facts, "Začít hru / Pravidla"
    rules      how the game is played
    intro      the moderator's welcome while the first question is prepared
    loading    the next question is prepared
    question   a question with answers, lifelines and the ladder (also while the answer is being evaluated)
    feedback   a right answer: explanation and the way on
    gameover   a wrong answer: both answers, what was reached, explanation
    win        the last question answered: the million
    results    the summary of a won game
    error      the moderator could not get his words

Every key is always present (empty when it does not apply), so a screen never shows a property of the previous one.
"""
import textwrap

from wcs.games.millionaire_prompts import MONEY_AMOUNTS

ROUNDS = 9
LETTERS = 'ABCD'
TIERS = (('easy', 'SNADNÁ', 1, 3), ('medium', 'STŘEDNÍ', 4, 6), ('hard', 'TĚŽKÁ', 7, 9))
KICKERS = {'movie': 'FILMOVÁ VÝZVA', 'series': 'SERIÁLOVÁ VÝZVA', 'channel': 'KANÁLOVÁ VÝZVA',
           'actor': 'HERECKÁ VÝZVA', 'director': 'REŽISÉRSKÁ VÝZVA', 'writer': 'SCENÁRISTICKÁ VÝZVA',
           'creator': 'TVŮRCOVSKÁ VÝZVA'}
SUBJECTS = {'movie': 'film', 'series': 'seriál', 'channel': 'kanál', 'actor': 'herce', 'director': 'režiséra',
            'writer': 'scénáristu', 'creator': 'tvůrce'}
SCREENS = {'intro': 'title', 'millionaire_welcome': 'title', 'millionaire_rules': 'rules',
           'generating_welcome': 'intro', 'welcome_screen': 'intro', 'generating_question': 'loading',
           'playing': 'question', 'answer_pending': 'question', 'generating_feedback': 'question',
           'answer_feedback': 'feedback', 'game_over': 'gameover', 'game_finished': 'win', 'error': 'error'}
# how many questions were answered right in each state (the current round is counted only once it is evaluated)
EVALUATED = ('answer_feedback', 'game_finished')


# the moderator's card of the answer screen: 5 lines of ~70 characters in its normal font (modern design); a longer
# text switches it to a narrow small font so that it still fits whole
MODERATOR_CHARS, MODERATOR_LINES = 70, 5


def moderator_small(*texts):
    """True when the texts would not fit the moderator's card in its normal font."""
    lines = sum(max(1, len(textwrap.wrap(text, MODERATOR_CHARS))) for text in texts if text and text.strip())
    return lines > MODERATOR_LINES


def money(round_num):
    return MONEY_AMOUNTS.get(round_num, '0 Kč') if round_num else '0 Kč'


def tier_of(round_num):
    """(key, label) of the difficulty of a round."""
    return next(((key, label) for key, label, first, last in TIERS if first <= round_num <= last), TIERS[-1][:2])


def screen_of(game):
    screen = SCREENS.get(game.game_state, 'title')
    if screen == 'win' and getattr(game, '_results_shown', False):
        return 'results'
    return screen


def completed(game):
    """Questions answered right so far."""
    if game.game_state == 'game_finished':
        return ROUNDS
    if game.game_state in EVALUATED:
        return game.current_round
    if game.game_state in ('title', 'millionaire_welcome', 'millionaire_rules', 'intro', 'generating_welcome',
                           'welcome_screen'):
        return 0
    return max(0, game.current_round - 1)


def _answer_states(game, screen):
    """State of every answer button: '' | removed | pending | correct | wrong."""
    question = game.current_question or {}
    options = question.get('options', [])
    states = []
    for index in range(4):
        text = options[index] if index < len(options) else ''
        if game.lifeline_5050_used and game.lifeline_5050_indices and index not in game.lifeline_5050_indices:
            text = ''
        if not text:
            states.append('removed')
        elif screen == 'question' and game.game_state == 'answer_pending' and index == getattr(game, 'selected_answer_index', -1):
            states.append('pending')
        else:
            states.append('')
    return states


def _tier_counts(done):
    result = {}
    for key, _label, first, last in TIERS:
        right = max(0, min(done, last) - first + 1)
        result[key] = '{}/{}'.format(right, last - first + 1)
    return result


def _ladder(game, screen, done):
    states = {}
    for number in range(1, ROUNDS + 1):
        if number <= done:
            states[number] = 'done'
        elif screen == 'question' and number == game.current_round:
            states[number] = 'current'
        elif screen == 'feedback' and number == game.current_round + 1:
            states[number] = 'current'          # after a right answer the ladder lights the next amount
        elif screen == 'gameover' and number == game.current_round:
            states[number] = 'failed'
        else:
            states[number] = 'todo'
    return states


def _help(game):
    """Tip card and audience poll: their state and texts."""
    tip = game.tip_view or {}
    poll = game.poll_view or {}
    results = list(poll.get('results') or [0, 0, 0, 0]) + [0, 0, 0, 0]
    return {
        'HelpKind': game.help_kind if (tip or poll) else '',
        'TipState': tip.get('state', ''),
        'TipText': tip.get('text', '') if tip.get('state') in ('ready', 'error') else '',
        'PollState': ('final' if poll.get('final') else 'running') if poll else '',
        'PollStatus': poll.get('status', ''),
        'PollA': str(results[0]), 'PollB': str(results[1]), 'PollC': str(results[2]), 'PollD': str(results[3]),
    }


def view(game):
    """The properties (name without the `WCS.Game.` prefix -> text) of the screen the game is on."""
    screen = screen_of(game)
    state = game.game_state
    done = completed(game)
    round_num = game.current_round if screen in ('question', 'feedback', 'gameover', 'loading') else 0
    question = game.current_question or {}
    options = question.get('options', []) if screen in ('question', 'feedback', 'gameover') else []
    options = list(options) + [''] * (4 - len(options))
    feedback = game.feedback_data or {}
    tier_key, tier_label = tier_of(game.current_round) if round_num else ('', '')
    subject = SUBJECTS.get(game.media_type, 'film')
    lives = {'5050': game.lifeline_5050_used, 'Tip': game.lifeline_tip_used, 'Audience': game.lifeline_audience_used}
    correct = question.get('correct', 0)
    chosen = getattr(game, 'selected_answer_index', 0)
    content = game.content
    states = _answer_states(game, screen)
    counts = _tier_counts(done)
    ladder = _ladder(game, screen, done)
    data = {
        'Screen': screen,
        'Kicker': KICKERS.get(game.media_type, KICKERS['movie']),
        'Subject': subject,
        'Tagline': getattr(content, 'tagline', '') or 'Jak dobře znáte {}?'.format(
            'tento film' if subject == 'film' else 'tento seriál' if subject == 'seriál' else subject),
        'WinLine': getattr(content, 'win_line', '') or 'Znáte {} do posledního detailu.'.format(game.title),
        'Round': str(round_num) if round_num else '',
        'RoundLabel': 'OTÁZKA {} / {}'.format(round_num, ROUNDS) if round_num else '',
        'TierKey': tier_key, 'TierLabel': tier_label,
        'Money': money(game.current_round) if round_num else '',
        'NextMoney': money(game.current_round + 1) if screen == 'feedback' and game.current_round < ROUNDS else '',
        'Earned': money(done),
        'QuestionText': question.get('question', '') if screen in ('question', 'feedback', 'gameover') else '',
        'OptA': options[0], 'OptB': options[1], 'OptC': options[2], 'OptD': options[3],
        'StateA': states[0], 'StateB': states[1], 'StateC': states[2], 'StateD': states[3],
        'Countdown': str(game.countdown) if game.countdown else '',
        'TipLabel': game._get_tip_text(short=True),
        'Life5050Used': 'true' if lives['5050'] else '', 'LifeTipUsed': 'true' if lives['Tip'] else '',
        'LifeAudienceUsed': 'true' if lives['Audience'] else '',
        'LivesUsed': str(sum(1 for used in lives.values() if used)),
        'Moderator': (game.moderator_welcome or '') if screen == 'intro' else '',
        'Loading': 'true' if state == 'generating_welcome' or screen == 'loading' or (
            screen == 'intro' and game.prefetched_question is None) else '',
        'Result': feedback.get('result_announcement', '') if screen in ('feedback', 'gameover', 'win') else '',
        'ModeratorSmall': 'true' if screen == 'feedback' and moderator_small(
            feedback.get('result_announcement', ''), feedback.get('transition_text', '')) else '',
        'Transition': feedback.get('transition_text', '') if screen in ('feedback', 'gameover', 'win') else '',
        'Explanation': question.get('explanation', '') if screen in ('feedback', 'gameover') else '',
        'YourLetter': LETTERS[chosen] if screen == 'gameover' else '',
        'YourText': options[chosen] if screen == 'gameover' else '',
        'RightLetter': LETTERS[correct] if screen in ('feedback', 'gameover') else '',
        'RightText': options[correct] if screen in ('feedback', 'gameover') else '',
        'CorrectCount': str(done), 'CorrectLabel': '{} z {}'.format(done, ROUNDS),
        'Score': '{} / {}'.format(done, ROUNDS),
        'TierEasy': counts['easy'], 'TierMedium': counts['medium'], 'TierHard': counts['hard'],
    }
    data.update(_help(game) if screen == 'question' else _help(_NoHelp))
    for number in range(1, ROUNDS + 1):
        data['Ladder.{}.State'.format(number)] = ladder[number]
    return data


class _NoHelp:
    """Stand-in game without a running lifeline (the help keys are empty outside the question screen)."""
    tip_view = poll_view = None
    help_kind = ''


def keys():
    """Every property name `view` sets (so a design can clear them all)."""
    probe = _Probe()
    return sorted(view(probe))


class _Probe:
    """A game at its very beginning, enough for `keys`."""
    game_state = 'intro'
    current_round = 1
    current_question = None
    feedback_data = None
    tip_view = poll_view = None
    help_kind = ''
    countdown = 0
    lifeline_5050_used = lifeline_tip_used = lifeline_audience_used = False
    lifeline_5050_indices = None
    media_type = 'movie'
    title = ''
    moderator_welcome = ''
    prefetched_question = None
    content = None

    @staticmethod
    def _get_tip_text(short=False):
        return ''
