# -*- coding: utf-8 -*-
"""Home rows of the Pro tebe section (docs/plan/pro-tebe/030): ListItems from the stored snapshot, never the network.

Rows `fy_*` go through the main.py fast path (rows.run -> here). Cards are drawn by the same builders as the library
rows (wcs/library2/rows.py), so cards, hero, clicks and the context menu behave the same; the hero gets the match
("94 % shoda") as its badge and the reason ("Protože jsi viděl Matrix") next to it. The snapshot is mode-specific
(all / movie / tv), chosen with the hero button "Zobrazit" (wcs/foryou/mode.py).
"""
import time

import xbmc
import xbmcaddon
import xbmcplugin

ADDON_ID = 'plugin.video.milionar'
POSTER = 'https://image.tmdb.org/t/p/w500'
BACKDROP = 'https://image.tmdb.org/t/p/w1280'

# row id -> snapshot row kind (and the n-th of its kind for the 'because' rows)
ROWS = {'fy_for_you': ('for_you', 0), 'fy_top10': ('top10', 0), 'fy_because_1': ('because', 0),
        'fy_because_2': ('because', 1), 'fy_because_3': ('because', 2), 'fy_tonight': ('tonight', 0),
        'fy_new': ('new', 0), 'fy_gems': ('gems', 0)}
CONTINUE = 'fy_continue'
ALL_ROWS = (CONTINUE,) + tuple(ROWS)

S_SECTION, S_CONTINUE, S_TOP, S_BECAUSE, S_LIKE = 35300, 35301, 35303, 35304, 35305
S_SLOTS = {'morning': 35306, 'afternoon': 35307, 'evening': 35308, 'night': 35309}
S_NEW, S_GEMS = 35310, 35311
REASONS = {'because_watched': 35304, 'because_liked': 35305, 'similar_to': 35305, 'because_list': 35312,
           'maker': 35313, 'actor': 35314, 'collection': 35315, 'genre': 35316, 'trending': 35317, 'quality': 35318}
S_MATCH, S_TOP_N = 35319, 35320
LANG_LABELS = {'cz_dub': 35325, 'cz_sub': 35326, 'sk_dub': 35327}
SHOWN_QUALITY = ('4K', '1080p')
FALLBACK = {35300: 'Pro tebe', 35301: 'Pokračovat', 35303: 'Top 10 v ČR', 35304: 'Protože jsi viděl {}',
            35305: 'Podobné jako {}', 35306: 'Na ráno', 35307: 'Na odpoledne', 35308: 'Na dnešní večer',
            35309: 'Na noc', 35310: 'Nově s CZ dabingem', 35311: 'Skryté klenoty', 35312: 'Podobné jako {} z tvého seznamu',
            35313: 'Od tvůrce {}', 35314: 'Hraje {}', 35315: 'Z kolekce {}', 35316: 'Tvůj žánr: {}', 35317: 'Teď frčí',
            35318: 'Vysoce hodnocené', 35319: '{} % shoda', 35320: 'TOP {}', 35325: 'CZ dabing',
            35326: 'CZ titulky', 35327: 'SK dabing'}


def _text(string_id):
    return xbmcaddon.Addon(ADDON_ID).getLocalizedString(string_id) or FALLBACK.get(string_id, '')


def _snapshot():
    from wcs.foryou import engine
    try:
        return engine.load()
    except Exception as exc:
        xbmc.log('[Milionář ProTebe] snapshot read failed: {}: {}'.format(type(exc).__name__, exc), xbmc.LOGWARNING)
        return None


def find_row(snapshot, row, mode='all'):
    kind, nth = ROWS[row]
    found = [r for r in (snapshot or {}).get('modes', {}).get(mode) or [] if r['kind'] == kind]
    return found[nth] if nth < len(found) else None


def reason_text(snapshot, reason):
    if not reason:
        return ''
    template = _text(REASONS.get(reason.get('kind'), 0)) if reason.get('kind') in REASONS else ''
    if not template:
        return ''
    arg = reason.get('arg') or snapshot.get('seed_titles', {}).get(reason.get('seed', ''), '')
    if reason['kind'] == 'genre':
        arg = snapshot.get('genres', {}).get(str(arg)) or ''
    if '{}' in template and not arg:
        return ''
    return template.format(arg) if '{}' in template else template


def row_title(snapshot, row, mode='all'):
    """Header of a row; the 'because' and time-of-day rows name their seed / slot, so they change with the snapshot."""
    if row == CONTINUE:
        return _text(S_CONTINUE)
    found = find_row(snapshot, row, mode) if snapshot else None
    kind = ROWS[row][0]
    if kind == 'because':
        if not found:
            return ''
        title = snapshot.get('seed_titles', {}).get(found['seed'], '')
        liked = (found.get('reason') or {}).get('kind') == 'because_liked'
        return _text(S_LIKE if liked else S_BECAUSE).format(title)
    if kind == 'tonight':
        return _text(S_SLOTS.get((found or {}).get('slot') or (snapshot or {}).get('slot') or 'evening', 35308))
    return _text({'for_you': S_SECTION, 'top10': S_TOP, 'new': S_NEW, 'gems': S_GEMS}[kind])


def _card(item):
    """A rows.py card from a snapshot item (titles that are not in the library: no watch state)."""
    genre = (item.get('genre_names') or [''])[0] if item.get('genre_names') else ''
    base = {'id': item['id'], 'title': item['title'], 'original': item.get('original_title') or item['title'],
            'year': str(item.get('year') or ''), 'rating': float(item.get('rating') or 0), 'plot': item.get('overview') or '',
            'poster': POSTER + item['poster'] if item.get('poster') else '',
            'fanart': BACKDROP + item['backdrop'] if item.get('backdrop') else '',
            'backdrop': item.get('backdrop') or '', 'genre': genre}
    if item['media'] == 'movie':
        base.update({'kind': 'movie', 'runtime': int(item.get('runtime') or 0), 'playcount': 0, 'resume': 0.0,
                     'resume_total': 0.0, 'time': 0, 'added': 0, 'activity': 0, 'hidden': False, 'played': False})
    else:
        base.update({'kind': 'tv', 'seasons': int(item.get('seasons') or 0), 'end_year': item.get('end_year') or '',
                     'ended': item.get('ended'), 'counts': [0, 0]})
    return base


def _with_genre_names(snapshot, item):
    names = snapshot.get('genres', {})
    return dict(item, genre_names=[names.get(str(g)) for g in item.get('genres') or [] if names.get(str(g))])


def build(row, params):
    """[(path, ListItem, folder)] of one Pro tebe row."""
    from wcs.library2 import clicks, rows
    from wcs.foryou import mode as section_mode
    if row == CONTINUE:
        items = _continue(params)
        section_mode.register(items, params.get('mode'))
        return items
    snapshot = _snapshot()
    mode = params.get('mode') if params.get('mode') in ('movie', 'tv') else 'all'
    found = find_row(snapshot, row, mode)
    if not found:
        return []
    limit = rows._limit(params)
    click = clicks.resolve(row, params.get('click') or '')
    landscape = params.get('style') == 'landscape'
    keys = [k for k in found['items'] if k in snapshot['items']][:limit]
    descriptors = []
    for key in keys:
        card = _card(_with_genre_names(snapshot, snapshot['items'][key]))
        descriptors.append({'kind': card['kind'], 'card': card, 'click': click, 'landscape': landscape,
                            'episode': None, 'episode_kind': ''})
    data = rows.Data()
    items = rows._render(rows._prepare(descriptors, data))
    row_reason = found.get('reason')
    for rank, (key, (_path, item, _folder)) in enumerate(zip(keys, items), 1):
        entry = snapshot['items'][key]
        if found['kind'] == 'top10':
            badge = _text(S_TOP_N).format(rank)
            item.setProperty('milionar.fy.rank', str(rank))      # the big number on the poster
        elif entry.get('match'):
            badge = _text(S_MATCH).format(entry['match'])
        else:
            badge = ''
        reason = reason_text(snapshot, row_reason if row_reason and row_reason.get('kind') != 'trending'
                             else entry.get('reason'))
        if found['kind'] == 'top10':
            reason = _text(REASONS['trending'])
        language = _language(entry)
        if language:                                        # 'AKČNÍ · 1999 · 2h 16m · CZ DABING · 4K'
            from wcs.skin import hero
            kicker = item.getProperty('milionar.hero.kicker')
            gap = hero.HAIR * 3 + ' ' + hero.HAIR * 3
            item.setProperty('milionar.hero.kicker', (kicker + gap if kicker else '') + hero.track('· ' + language if kicker else language))
            item.setProperty('milionar.fy.lang', language)
        if entry.get('logo'):
            item.setProperty('milionar.hero.title_image', entry['logo'])     # the hero shows the logo, not the text
        item.setProperty('milionar.hero.badge', badge.upper())
        item.setProperty('milionar.hero.now', reason if badge else '')
        item.setProperty('milionar.fy.match', str(entry.get('match') or ''))
        item.setProperty('milionar.fy.reason', reason)
    if row == 'fy_for_you' and needs_pick(snapshot):          # after the loop: the card takes no title's texts
        items = [_pick_card(snapshot, keys)] + items
    section_mode.register(items, params.get('mode'))
    return items


def _language(entry):
    label = _text(LANG_LABELS[entry['lang']]) if entry.get('lang') in LANG_LABELS else ''
    if label and entry.get('quality') in SHOWN_QUALITY:
        label += ' · ' + entry['quality']
    return label.upper()


STRONG = ('watched', 'like', 'pick')
MIN_STRONG = 3


def needs_pick(snapshot):
    """Too little taste yet (a new household, a few films opened): offer the first-run pick."""
    return sum(1 for s in snapshot.get('seeds') or [] if s.get('kind') in STRONG and s.get('weight', 0) > 0) < MIN_STRONG


def _pick_card(snapshot, keys):
    """The first card of Pro tebe for a household without taste: 'Vyber, co máš rád' opens the pick dialog."""
    import xbmcgui
    from wcs.foryou import feedback
    from wcs.skin import hero
    title = feedback.text(feedback.S_PICK_CARD)
    run = 'RunPlugin(plugin://{}/?action=foryou_pick)'.format(ADDON_ID)
    path = 'plugin://{}/?action=skin_run&run={}'.format(ADDON_ID, 'action%3Dforyou_pick')
    item = xbmcgui.ListItem(label=title, path=path, offscreen=True)
    item.setArt({'poster': 'DefaultFavourites.png', 'thumb': 'DefaultFavourites.png', 'icon': 'DefaultFavourites.png'})
    texts = {'title': title, 'size': hero.size(title), 'kicker': hero.track(feedback.text(35341).upper()), 'rating': '',
             'plot': feedback.text(35340), 'left': '', 'note': '', 'fanart': '',
             'badge': feedback.text(35342).upper(), 'now': feedback.text(35343)}
    hero.apply(item, texts, run, '', ids=('play', ''), labels=(title, ''))
    item.setProperty('milionar.exec', run)
    return path, item, False


def _continue(params):
    """Pokračovat: the films in progress and the next episodes, the latest activity first, as wide cards."""
    from wcs.library2 import rows
    limit = rows._limit(params)
    data = rows.Data()
    mode = params.get('mode')
    films = [] if mode == 'tv' else rows._build('cont_movies', dict(params, limit=str(limit), style='landscape',
                                                                       sort='activity'), data)
    series = [] if mode == 'movie' else rows._build('cont_series', dict(params, limit=str(limit), sort='activity'), data)
    merged = sorted(films + series, key=lambda d: -(d['card'].get('activity') or d['card'].get('time') or 0))[:limit]
    return rows._render(rows._prepare(merged, data))


def _set_title(params, title):
    """The row header is the slot's skin string: keep it in step with the snapshot (seed / time of day)."""
    sec, slot = params.get('sec'), params.get('slot')
    if not sec or not slot or not title:
        return
    from wcs.skin import slots
    slots._set('mil.{}.{}.title'.format(sec, slot), title)


def run(handle, params):
    started = time.perf_counter()
    row = params.get('row', '')
    items = []
    try:
        items = build(row, params)
        snapshot = _snapshot() if row != CONTINUE else None
        mode = params.get('mode') if params.get('mode') in ('movie', 'tv') else 'all'
        _set_title(params, row_title(snapshot, row, mode))
    except Exception as exc:                              # a broken row must never break Home
        xbmc.log('[Milionář ProTebe] row {} failed: {}: {}'.format(row, type(exc).__name__, exc), xbmc.LOGERROR)
    xbmcplugin.addDirectoryItems(handle, items, len(items))
    xbmcplugin.endOfDirectory(handle, succeeded=True, cacheToDisc=False)
    xbmc.log('[Milionář ProTebe] widget_row {} -> {} items in {:.0f} ms'.format(
        row, len(items), (time.perf_counter() - started) * 1000), xbmc.LOGDEBUG)
