# -*- coding: utf-8 -*-
"""Explicit Vinyl detail opens: a music card with track list and existing playback/actions."""
import xbmc
import xbmcgui
from urllib.parse import parse_qsl, urlsplit

from wcs.vinyl import actions, client, presentation, widgets


def cached_entry(params):
    kind = params['kind']
    sources = [source for source, entry_kind, _label in widgets.ROWS.values() if entry_kind == kind]
    for source in sources:
        for entry in client.cached(source):
            query = widgets.query(entry, kind)
            if (str(query['id']) == str(params.get('id', '')) and query['name'] == params.get('name', '')):
                return dict(entry)
    return {'id': params.get('id'), 'name': params.get('name', ''), 'artist': params.get('artist', '')}


def load(params, offset=0):
    """Only this interactive path fetches tracks. Album/artist/genre remain paged."""
    kind = params['kind']
    entry = cached_entry(params)
    if kind == 'playlist':
        entry.update(client.request('playlists/{}'.format(int(params['id']))))
        songs = entry.get('songs') or []
        entry.update(song_count=len(songs), total_duration=sum(int(song.get('duration') or 0) for song in songs))
        more = False
    elif kind == 'song':
        entry = client.request('songs/{}'.format(int(params['id'])))
        songs, more = [entry], False
    elif kind == 'radio':
        songs, more = actions._songs(params), False
    else:
        songs, more = client.song_page(client.collection_path(
            kind, params.get('id', ''), params.get('name', ''), params.get('artist', '')), offset)
    return entry, songs, more


def options(params, dialog=None):
    from wcs.skin.context import open_menu
    chosen = open_menu(dict(cached_entry(params), **dict(params, type='vinyl')), execute=False)
    if not chosen:
        return
    args = dict(parse_qsl(urlsplit(chosen[10:-1]).query)) if chosen.startswith('RunPlugin(') else {}
    if dialog and args.get('action') == 'vinyl_context':
        from wcs.vinyl import context
        if client.scope() != dialog.session:
            dialog.close()
            return
        with widgets.defer_refresh():
            changed = context.run(args)
        if not changed:
            return
        if args.get('op') == 'delete_playlist' and args.get('id') == dialog.params.get('id'):
            dialog.close()
        else:
            selected = dialog.getControl(500).getSelectedPosition()
            entry, songs, more = load(dialog.params, dialog.offset)
            if client.scope() == dialog.session:
                dialog.entry, dialog.songs, dialog.more = entry, songs, more
                dialog._publish()
                if songs:
                    dialog.getControl(500).selectItem(min(selected, len(songs) - 1))
    else:
        xbmc.executebuiltin(chosen)


class VinylDetail(xbmcgui.WindowXMLDialog):
    def __init__(self, *args, **kwargs):
        self.params = kwargs.pop('params')
        self.session = kwargs.pop('session')
        self.entry, self.songs, self.more = kwargs.pop('data')
        self.offset = 0
        super().__init__(*args, **kwargs)

    def onInit(self):
        self._publish()

    def _publish(self):
        from wcs.vinyl import context
        values = presentation.fields(self.entry, self.params['kind'], self.params)
        for key, value in values.items():
            self.setProperty('vinyl.' + key, str(value))
        self.setProperty('vinyl.description', self.entry.get('description') or values['plot'])
        can_favorite = bool(self.session[0]) and self.params['kind'] in ('song', 'playlist', 'album', 'artist')
        state = context.favorite(dict(self.entry, **self.params)) if can_favorite else None
        self.setProperty('vinyl.can_favorite', '1' if can_favorite and state is not None else '')
        self.setProperty('vinyl.favorite_label', presentation.text(32613 if state else 32612))
        self.setProperty('vinyl.can_shuffle', '1' if self.params['kind'] not in ('song', 'radio') else '')
        self.setProperty('vinyl.previous', '1' if self.offset else '')
        self.setProperty('vinyl.next', '1' if self.more else '')
        self.setProperty('vinyl.page', '{}–{}'.format(self.offset + 1, self.offset + len(self.songs)) if self.songs else '')
        control = self.getControl(500)
        control.reset()
        cards = []
        for index, song in enumerate(self.songs):
            item = xbmcgui.ListItem(song.get('title') or '', offscreen=True)
            item.setArt({'thumb': client.cover(song, 'song')})
            item.setProperty('vinyl.number', str(self.offset + index + 1))
            item.setProperty('vinyl.artist', song.get('artist') or '')
            item.setProperty('vinyl.duration', presentation.duration(song.get('duration')))
            cards.append(item)
        control.addItems(cards)

    def _song_params(self):
        index = self.getControl(500).getSelectedPosition()
        if not 0 <= index < len(self.songs):
            return None
        song = self.songs[index]
        values = widgets.query(song, 'song', self.params.get('row', ''), 'play')
        values.update(album=song.get('album', ''), album_id=song.get('album_id', ''),
                      ids=','.join(str(s['id']) for s in self.songs), ctx=self.params.get('ctx', ''),
                      is_favorite=song.get('is_favorite', ''))
        if self.params['kind'] == 'playlist':
            values.update(parent_playlist=self.params['id'],
                          owner='1' if str(self.entry.get('user_id')) == self.session[0] else '')
        return values

    def onClick(self, control_id):
        if control_id == 106:
            self.close()
            return
        if client.scope() != self.session:
            self.close()
            return
        try:
            if control_id in (101, 102):
                mode = 'shuffle' if control_id == 102 else 'play_all'
                songs = actions._songs(self.params) if self.params['kind'] in ('album', 'artist', 'genre') else self.songs
                actions._play(songs, mode)
            elif control_id == 103:
                from wcs.vinyl import context
                with widgets.defer_refresh():
                    context.run(dict(self.params, op='favorite'))
                # Re-read the explicit detail for authoritative favorite state.
                entry, songs, more = load(self.params, self.offset)
                if client.scope() == self.session:
                    self.entry, self.songs, self.more = entry, songs, more
                    if self.params['kind'] in ('album', 'artist'):
                        source = 'favorite_' + self.params['kind'] + 's'
                        entries = client.sources([source])[source]
                        query = widgets.query(self.entry, self.params['kind'])
                        self.entry['is_favorite'] = any(widgets.query(e, self.params['kind'])['id'] == query['id'] and
                            widgets.query(e, self.params['kind'])['name'] == query['name'] and
                            (self.params['kind'] != 'album' or widgets.query(e, self.params['kind'])['artist'] == query['artist'])
                            for e in entries)
                    self._publish()
            elif control_id == 104:
                options(self.params, self)
            elif control_id == 500:
                index = self.getControl(500).getSelectedPosition()
                if 0 <= index < len(self.songs):
                    actions._play(self.songs[index:], 'play_all')
            elif control_id in (107, 108):
                offset = max(0, self.offset + (-client.PAGE_SIZE if control_id == 107 else client.PAGE_SIZE))
                entry, songs, more = load(self.params, offset)
                if client.scope() == self.session:
                    self.entry, self.songs, self.more, self.offset = entry, songs, more, offset
                    self._publish()
                    self.setFocusId(500 if songs else 106)
        except Exception as exc:
            xbmc.log('[Milionář Vinyl] detail action failed: {}'.format(type(exc).__name__), xbmc.LOGWARNING)
            xbmcgui.Dialog().notification('Vinyl', presentation.text(32532), xbmcgui.NOTIFICATION_ERROR)

    def onAction(self, action):
        if client.scope() != self.session:
            self.close()
            return
        if action.getId() in (9, 10, 92):
            self.close()
        elif action.getId() == 117 and self.getFocusId() == 500:
            params = self._song_params()
            if params:
                try:
                    options(params, self)
                except Exception as exc:
                    xbmc.log('[Milionář Vinyl] detail menu failed: {}'.format(type(exc).__name__), xbmc.LOGWARNING)
                    xbmcgui.Dialog().notification('Vinyl', presentation.text(32532), xbmcgui.NOTIFICATION_ERROR)


def open_detail(params):
    session = client.scope()
    data = load(params)
    if client.scope() != session:
        return
    dialog = VinylDetail('vinyl/DialogVinylDetail.xml', client.addon().getAddonInfo('path'),
                         'Default', '1080i', params=params, session=session, data=data)
    dialog.doModal()
    del dialog
