# -*- coding: utf-8 -*-
"""Video action eligibility and labels from the library store and metadata cache.

Menu layouts and editing live in wcs.skin.context. Provider entry points only describe an item.
"""
from urllib.parse import quote, quote_plus

import xbmcaddon

from wcs.library2 import next_up, rows

ADDON_ID = 'plugin.video.milionar'
BASE = 'plugin://{}/'.format(ADDON_ID)

S_RESUME, S_RESTART, S_PLAY, S_SOURCE, S_NEXT = 32400, 32401, 32402, 32403, 32404
S_WATCHED, S_UNWATCHED, S_HIDE = 32405, 32406, 32407
S_ADD_MOVIES, S_REMOVE_MOVIES, S_ADD_SERIES, S_REMOVE_SERIES = 32408, 32409, 32410, 32411
S_MYTV, S_MYCINEMA, S_DETAIL, S_SIMILAR, S_COLLECTION, S_GAME = 32412, 32413, 32414, 32415, 32416, 32417
S_MORE = 32420


def _plugin(query):
    return 'RunPlugin({}?{})'.format(BASE.rstrip('/'), query)


def _mmss(seconds):
    seconds = int(seconds)
    return '{}:{:02d}:{:02d}'.format(seconds // 3600, seconds % 3600 // 60, seconds % 60) if seconds >= 3600 \
        else '{:02d}:{:02d}'.format(seconds // 60, seconds % 60)


class Menu:
    def __init__(self, data=None):
        self.data = data or rows.Data()
        self._addon = xbmcaddon.Addon(ADDON_ID)
        self._labels = {}

    def text(self, string_id):
        if string_id not in self._labels:
            self._labels[string_id] = self._addon.getLocalizedString(string_id)
        return self._labels[string_id]

    # ------------------------------------------------------------ playback
    def _play_items(self, kind, tmdb_id, season, episode):
        data, items = self.data, []
        if kind in ('movie', 'episode'):
            state = (data.movie_states().get(tmdb_id) if kind == 'movie'
                     else data.episode_states().get(tmdb_id, {}).get((season, episode))) or {}
            query = ('type=movie&tmdb={}'.format(tmdb_id) if kind == 'movie'
                     else 'type=episode&tmdb={}&s={}&e={}'.format(tmdb_id, season, episode))
            src = 'last' if state.get('last_ident') else 'dialog'
            resume = float(state.get('resume_pos') or 0)
            if resume > 0:
                items.append((self.text(S_RESUME).format(_mmss(resume)), _plugin('action=mplay_req&{}&src={}&from=resume'.format(query, src))))
                items.append((self.text(S_RESTART), _plugin('action=mplay_req&{}&src={}&from=start'.format(query, src))))
            else:
                items.append((self.text(S_PLAY), _plugin('action=mplay_req&{}&src={}&from=start'.format(query, src))))
            items.append((self.text(S_SOURCE), _plugin('action=mplay_req&{}&src=dialog&from=start'.format(query))))
        else:                                                           # series, season: the next episode
            _show, order, state = data.series_state(tmdb_id)
            target = state['episode'] if state['kind'] in ('resume', 'next') else None
            if state['kind'] is None and order and order[0]['aired']:
                target = order[0]
            if target:
                items.append((self.text(S_NEXT).format('S{:02d}E{:02d}'.format(target['s'], target['e'])),
                              _plugin('action=mplay_req&type=episode&tmdb={}&s={}&e={}&src=auto&from=start'.format(
                                  tmdb_id, target['s'], target['e']))))
        return items

    # ------------------------------------------------------------ state
    def is_watched(self, kind, tmdb_id, season=None, episode=None):
        """Movie / episode: played; series / season: every aired episode played."""
        data = self.data
        if kind == 'movie':
            return int((data.movie_states().get(tmdb_id) or {}).get('playcount') or 0) > 0
        if kind == 'episode':
            return int((data.episode_states().get(tmdb_id, {}).get((season, episode)) or {}).get('playcount') or 0) > 0
        _show, order, _state = data.series_state(tmdb_id)
        states = data.episode_states().get(tmdb_id, {})
        scope = [e for e in order if e['aired'] and (kind == 'tv' or e['s'] == season)]
        return bool(scope) and all(int((states.get((e['s'], e['e'])) or {}).get('playcount') or 0) > 0 for e in scope)

    def _state_items(self, kind, tmdb_id, season, episode):
        items = []
        watched = self.is_watched(kind, tmdb_id, season, episode)
        query = 'type={}&tmdb={}'.format(kind, tmdb_id) + ('&s={}'.format(season) if season is not None else '') \
            + ('&e={}'.format(episode) if episode is not None else '')
        items.append((self.text(S_UNWATCHED if watched else S_WATCHED),
                      _plugin('action=ctx_mark&{}&watched={}'.format(query, 0 if watched else 1))))
        if self._in_continue(kind, tmdb_id):
            items.append((self.text(S_HIDE), _plugin('action=ctx_hide_continue&type={}&tmdb={}'.format(
                'movie' if kind == 'movie' else 'tv', tmdb_id))))
        return items

    def _in_continue(self, kind, tmdb_id):
        media = 'movie' if kind == 'movie' else 'tv'
        row = self.data.titles(media).get(tmdb_id) or {}
        if row.get('hidden_from_continue_at'):
            return False
        if kind == 'movie':
            return float((self.data.movie_states().get(tmdb_id) or {}).get('resume_pos') or 0) > 0
        return bool(row.get('last_activity_at'))

    # ------------------------------------------------------------ lists and channels
    def _list_items(self, kind, tmdb_id):
        movie = kind == 'movie'
        listed = bool((self.data.titles('movie' if movie else 'tv').get(tmdb_id) or {}).get('in_list'))
        label = (S_REMOVE_MOVIES if listed else S_ADD_MOVIES) if movie else (S_REMOVE_SERIES if listed else S_ADD_SERIES)
        items = [(self.text(label), _plugin('action=ctx_list&type={}&tmdb={}&add={}'.format(
            'movie' if movie else 'tv', tmdb_id, 0 if listed else 1)))]
        items.append((self.text(S_MYCINEMA if movie else S_MYTV),
                      _plugin('action=ctx_channel&type={}&tmdb={}'.format('movie' if movie else 'tv', tmdb_id))))
        return items

    # ------------------------------------------------------------ discovery
    def _discovery_items(self, kind, tmdb_id, season, episode, title=''):
        movie = kind == 'movie'                                        # kind: movie | tv | season | episode
        media = 'movie' if movie else 'tv'
        detail = self.data.movie(tmdb_id) if movie else self.data.show(tmdb_id)
        snapshot = self.data.snapshot(media, tmdb_id) or {}
        title = (detail.get('title') if movie else detail.get('name')) or snapshot.get('title') or snapshot.get('name') or title
        items = [(self.text(S_DETAIL), _plugin('action=show_wcs_details&media_type={}&tmdb_id={}'.format(media, tmdb_id)))]
        original = detail.get('original_title') or detail.get('original_name') or title
        items.append((self.text(S_SIMILAR), _plugin('action=display_similar_{}_dialog&tmdb_id={}&original_title={}'.format(
            'movies' if movie else 'series', tmdb_id, quote_plus(original)))))
        if movie and detail.get('belongs_to_collection'):
            items.append((self.text(S_COLLECTION), 'ActivateWindow(Videos,{}?action=show_movie_collection&tmdb_id={},return)'.format(
                BASE.rstrip('/'), tmdb_id)))
        poster = rows._image(rows.POSTER, detail.get('poster_path'))
        from wcs.games import millionaire
        game = millionaire.query(millionaire.Subject(
            title=title, tmdb_id=str(tmdb_id), media_type=media, plot=detail.get('overview') or '', poster=poster,
            year=(detail.get('release_date') or detail.get('first_air_date') or '')[:4],
            season_number=season if kind in ('season', 'episode') else None,
            episode_number=episode if kind == 'episode' else None))
        items.append((self.text(S_GAME), _plugin(game)))
        return items

    def build_parts(self, kind, tmdb_id, season=None, episode=None, title=''):
        """Compatibility with callers of the old builder; layout belongs to the shared manager."""
        from wcs.skin import context
        return context.parts({'type': kind, 'tmdb': str(tmdb_id), 's': season, 'e': episode, 'title': title})

    def build(self, kind, tmdb_id, season=None, episode=None, title=''):
        from wcs.skin import context
        return context.entry({'type': kind, 'tmdb': str(tmdb_id), 's': season, 'e': episode, 'title': title})


def attach(item, menu, kind, tmdb_id, season=None, episode=None):
    """Put the menu on a ListItem; a failing menu never breaks a listing."""
    try:
        from wcs.skin import context
        data = context.unpack(item.getProperty('milionar.ctxdata'))
        data.update(type=kind, tmdb=str(tmdb_id), s=season, e=episode, title=item.getLabel())
        item.setProperty('milionar.ctxdata', context.pack(data))
        item.addContextMenuItems(context.entry(data), True)
    except Exception as exc:                                                   # pragma: no cover - defensive
        import xbmc
        xbmc.log('[Milionář Library] context menu failed: {}: {}'.format(type(exc).__name__, exc), xbmc.LOGWARNING)


def attach_items(items, data=None):
    """Context menu on every [(path, ListItem, is_folder)] that carries `milionar.type` (movie / tv / season / episode);
    not on the "all seasons" folder, unaired episodes and the buttons."""
    menu = Menu(data)
    for path, item, _folder in items:
        kind = item.getProperty('milionar.type')
        tmdb_id = item.getProperty('milionar.tmdb')
        if kind not in ('movie', 'tv', 'season', 'episode') or not tmdb_id or 'mupcoming' in path:
            continue
        season, episode = item.getProperty('milionar.s'), item.getProperty('milionar.e')
        if season == '-1':
            continue
        attach(item, menu, kind, int(tmdb_id), int(season) if season != '' else None, int(episode) if episode != '' else None)
