# -*- coding: utf-8 -*-
"""The settings screen of the Millionaire game: the addon settings of the game (all but the voice) as rows.

The screen is an overlay of the title card (WCS.Game.Settings); this module is what it shows and changes. A row is a
setting of the addon (resources/settings.xml, category "Hra Milionář"): changing it here writes the very same addon
setting, so the screen and the addon settings are one thing and the game reads them as it always did when it begins
(difficulty, text lengths, style) or when a round starts (auto-play). Nothing here has a value of its own.

    kind 'select'  an index into `options` (string ids of the language files), stored as the index
    kind 'bool'    stored as true / false
    kind 'slider'  a whole number between `low` and `high`, stored as text

Keys and setting ids never change independently: the XML (scripts/game_dialog/gen_modern_game.py) reads the
properties `WCS.Game.Set.<key>` this module publishes.
"""
from typing import NamedTuple, Optional, Tuple

PREFIX = 'WCS.Game.Set.'
ADDON_ID = 'plugin.video.milionar'


class Row(NamedTuple):
    key: str
    setting: str                       # id of the addon setting
    kind: str                          # select | bool | slider
    label: int                         # string id of the row's name
    description: int                   # string id of what the row does
    default: object
    options: Tuple[int, ...] = ()      # select: string ids of the choices
    low: int = 0
    high: int = 0
    unit: str = ''                     # slider: text after the number
    needs: Optional[str] = None        # key of a bool row that has to be on for this row to show
    group: str = 'game'                # game | spectator


LENGTHS = (35230, 35231, 35232, 35233)
ROWS = (
    Row('difficulty', 'millionaire_difficulty', 'select', 32107, 35260, 1, options=(32108, 32109, 32110)),
    Row('style', 'milionar_moderator_style', 'select', 35245, 35261, 2, options=(35020, 35021, 35022, 35023, 35024)),
    Row('len_welcome', 'milionar_len_welcome', 'select', 35222, 35262, 2, options=LENGTHS),
    Row('len_intro', 'milionar_len_intro', 'select', 35223, 35263, 1, options=LENGTHS),
    Row('len_result', 'milionar_len_result', 'select', 35224, 35264, 2, options=LENGTHS),
    Row('len_transition', 'milionar_len_transition', 'select', 35225, 35265, 1, options=LENGTHS),
    Row('len_explanation', 'milionar_len_explanation', 'select', 35226, 35266, 1, options=LENGTHS),
    Row('autoplay', 'milionar_autoplay', 'bool', 35201, 35267, False, group='spectator'),
    Row('autoplay_fail_round', 'milionar_autoplay_fail_round', 'select', 35246, 35268, 0,
        options=(35202, 35203, 35204, 35205, 35206, 35207), needs='autoplay', group='spectator'),
    Row('autoplay_speed', 'milionar_autoplay_speed', 'slider', 35208, 35269, 5, low=2, high=10, unit=' s',
        needs='autoplay', group='spectator'),
    Row('autoplay_lifelines', 'milionar_autoplay_lifelines', 'select', 35247, 35270, 1,
        options=(35210, 35211, 35212, 35213), needs='autoplay', group='spectator'),
)
STORY_ROW = Row('story_difficulty', 'story_difficulty', 'select', 35402, 35403, 1,
                options=(32108, 32109, 32110))
BY_KEY = {row.key: row for row in ROWS + (STORY_ROW,)}
FIRST_CONTROL = 9701                   # control ids of the rows of the screen, in the order of ROWS
CONTROLS = {row.key: FIRST_CONTROL + index for index, row in enumerate(ROWS)}
CONTROLS[STORY_ROW.key] = 9720
BY_CONTROL = {control: BY_KEY[key] for key, control in CONTROLS.items()}
ON, OFF = 35248, 35249                 # "Zapnuto" / "Vypnuto"


def _addon():
    import xbmcaddon
    return xbmcaddon.Addon(ADDON_ID)


def _text(string_id):
    """A string of the addon in the language of Kodi (the addon's own language files, not Kodi's core strings)."""
    return _addon().getLocalizedString(string_id)


def value_of(row, addon=None):
    """The current value of a row, read from the addon setting (the default when it is empty or invalid)."""
    raw = (addon or _addon()).getSetting(row.setting)
    if row.kind == 'bool':
        return raw == 'true' if raw in ('true', 'false') else bool(row.default)
    try:
        number = int(raw)
    except (TypeError, ValueError):
        return row.default
    if row.kind == 'select':
        return number if 0 <= number < len(row.options) else row.default
    return min(row.high, max(row.low, number))


def store(row, value, addon=None):
    """Write a value into the addon setting and return it."""
    (addon or _addon()).setSetting(row.setting, 'true' if value is True else 'false' if value is False else str(value))
    return value


def step(row, delta, addon=None, wrap=False):
    """Move a row's value by `delta` (-1 / +1) and store it; selects and bools wrap around only when `wrap`."""
    addon = addon or _addon()
    current = value_of(row, addon)
    if row.kind == 'bool':
        return store(row, not current if delta else current, addon)
    low, high = (0, len(row.options) - 1) if row.kind == 'select' else (row.low, row.high)
    new = current + delta
    if new > high:
        new = low if wrap else high
    elif new < low:
        new = high if wrap else low
    return store(row, new, addon)


def cycle(row, addon=None):
    """OK on a row: the next value, after the last the first one."""
    return step(row, 1, addon, wrap=True)


def visible(row, addon=None):
    return row.needs is None or bool(value_of(BY_KEY[row.needs], addon))


def text_of(row, addon=None, translate=None):
    """The value of a row as the player reads it ("Střední", "Zapnuto", "5 s")."""
    translate = translate or _text
    value = value_of(row, addon)
    if row.kind == 'bool':
        return translate(ON if value else OFF)
    if row.kind == 'slider':
        return '{}{}'.format(value, row.unit)
    return translate(row.options[value])


def rows_for(mode):
    return (STORY_ROW,) if mode == 'story' else ROWS


def properties(addon=None, translate=None, rows=None):
    """name -> text of every property the settings screen reads (the values; `Show` is 'true' for a visible row)."""
    translate = translate or _text
    addon = addon or _addon()
    values = {}
    for row in ROWS if rows is None else rows:
        values[PREFIX + row.key] = text_of(row, addon, translate)
        values[PREFIX + row.key + '.Show'] = 'true' if visible(row, addon) else ''
    return values


def choices(row, addon=None, translate=None):
    """All the values a row can take, one per line, the current one in gold (for the card of the focused row)."""
    translate = translate or _text
    value = value_of(row, addon)
    if row.kind == 'slider':
        return '{} – {}{}'.format(row.low, row.high, row.unit)
    names = [translate(ON), translate(OFF)] if row.kind == 'bool' else [translate(option) for option in row.options]
    current = (0 if value else 1) if row.kind == 'bool' else value
    return '[CR]'.join('[COLOR FFE8B860][B]•  {}[/B][/COLOR]'.format(name) if index == current
                       else '[COLOR FF8E909A]    {}[/COLOR]'.format(name) for index, name in enumerate(names))


def describe(row, addon=None, translate=None):
    """(name, value, description) of a row for the card that explains the focused row."""
    translate = translate or _text
    return translate(row.label), text_of(row, addon, translate), translate(row.description)
