# -*- coding: utf-8 -*-
"""Account UI, music browsing and native Kodi audio playlists."""
import random
from urllib.parse import urlencode

import xbmc
import xbmcgui
import xbmcplugin

from wcs.vinyl import client, widgets

BASE = widgets.BASE


def _offset(params):
    return max(0, int(params.get('offset', 0))) // client.PAGE_SIZE * client.PAGE_SIZE


def _pages(items, params, offset, more):
    for target, label in ((offset - client.PAGE_SIZE, 31855), (offset + client.PAGE_SIZE, 31856)):
        if target < 0 or (target > offset and not more):
            continue
        path = BASE + '?' + urlencode(dict(params, offset=target))
        li = xbmcgui.ListItem(client.addon().getLocalizedString(label), path=path, offscreen=True)
        li.setArt({'icon': 'DefaultFolder.png'})
        items.append((path, li, True))


def refresh_soon(sources=None):
    from wcs.skin.refresh import request
    selected = widgets.configurations() if sources is None else sources
    request(['vinyl_' + source for source in selected])


def _account_changed(previous):
    from wcs.skin.refresh import changed
    if previous != client.account():
        changed(list(widgets.ROWS))
    refresh_soon()


def login():
    settings = client.addon()
    name = xbmcgui.Dialog().input(settings.getLocalizedString(32516), settings.getSetting('vinyl_status'))
    if not name:
        return
    pin = xbmcgui.Dialog().input(settings.getLocalizedString(32517), type=xbmcgui.INPUT_ALPHANUM,
                               option=xbmcgui.ALPHANUM_HIDE_INPUT)
    if not pin:
        return
    previous = client.account()
    try:
        user = client.login(name, pin)
    except Exception:
        xbmcgui.Dialog().ok('Vinyl', settings.getLocalizedString(32519))
        return
    _account_changed(previous)
    xbmcgui.Dialog().notification('Vinyl', settings.getLocalizedString(32520).format(user))


def logout():
    previous = client.account()
    try:
        client.logout()
    except Exception:
        pass
    if previous:
        _account_changed(previous)


def _songs(params):
    kind, identity = params.get('kind'), params.get('id')
    if kind == 'song':
        if params.get('click') == 'play_from':
            source = widgets.ROWS.get(params.get('row'), ('songs',))[0]
            songs = client.cached(source)
            if params.get('ids'):
                ids = params['ids'].split(',')
                by_id = {str(s['id']): s for s in songs}
                by_id.update({str(s['id']): s for s in client.cached('songs')})
                missing = [int(i) for i in ids if i not in by_id]
                for offset in range(0, len(missing), 200):
                    by_id.update({str(s['id']): s for s in client.request('browse/songs/by-ids', 'POST',
                                                                         {'ids': missing[offset:offset + 200]})})
                songs = [by_id[i] for i in ids if i in by_id]
            for i, song in enumerate(songs):
                if str(song['id']) == str(identity):
                    return songs[i:]
        return [client.request('songs/{}'.format(int(identity)))]
    return client.collection(kind, identity, params.get('name', ''), params.get('artist', ''))


def _audio_item(song):
    url = song.get('_url') or client.media('stream/{}'.format(song['id']))
    li = xbmcgui.ListItem(song.get('title') or '', path=url, offscreen=True)
    tag = li.getMusicInfoTag()
    tag.setTitle(song.get('title') or '')
    tag.setArtist(song.get('artist') or '')
    tag.setAlbum(song.get('album') or '')
    tag.setDuration(int(song.get('duration') or 0))
    tag.setMediaType('song')
    if song.get('id'):
        li.setArt({'thumb': client.cover(song, 'song')})
    li.setProperty('IsPlayable', 'true')
    return url, li


def _play(songs, mode):
    if not songs:
        xbmcgui.Dialog().notification('Vinyl', client.addon().getLocalizedString(32529))
        return
    songs = list(songs)
    if mode == 'shuffle':
        random.shuffle(songs)
    playlist = xbmc.PlayList(xbmc.PLAYLIST_MUSIC)
    if mode != 'queue':
        playlist.clear()
    for song in songs:
        url, li = _audio_item(song)
        playlist.add(url, li)
    if mode != 'queue':
        xbmc.executebuiltin('PlayerControl(RandomOff)')
        xbmc.Player().play(playlist)
    else:
        xbmcgui.Dialog().notification('Vinyl', client.addon().getLocalizedString(32531))


def browse(handle, params):
    row = params.get('row')
    if row in widgets.ROWS:
        source, kind, _title = widgets.ROWS[row]
        if not client.account() and source not in client.PUBLIC_SOURCES:
            raise client.LoginRequired()
        offset = _offset(params)
        if source == 'top_tracks':
            entries = client.sources([source])[source]
            more = False
        elif kind == 'song':
            path = ('songs/favorites' if source == 'favorite_songs' else 'songs') + '?sort=created_at&order=DESC'
            entries, more = client.song_page(path, offset)
        else:
            entries = client.sources([source])[source]
        if kind == 'song':
            queue = ','.join(str(e['id']) for e in entries)
            entries = [dict(e, _queue=queue) for e in entries]
        items = [widgets.item(e, kind, row, 'play' if kind == 'song' else 'open', listing=True) for e in entries]
        if kind == 'song':
            _pages(items, params, offset, more)
    else:
        rows = [r for r in widgets.ROWS if not r.startswith('vinyl_favorite_')]
        items = []
        for r in rows:
            path = BASE + '?' + urlencode({'action': 'vinyl_browse', 'row': r})
            li = xbmcgui.ListItem(client.addon().getLocalizedString(widgets.ROWS[r][2]), path=path, offscreen=True)
            li.setArt({'icon': 'DefaultFolder.png'})
            items.append((path, li, True))
        path = BASE + '?action=vinyl_favorites'
        items.append((path, xbmcgui.ListItem(client.addon().getLocalizedString(32509), offscreen=True), True))
    xbmcplugin.setContent(handle, 'songs' if row and widgets.ROWS[row][1] == 'song' else 'albums')
    xbmcplugin.addDirectoryItems(handle, items, len(items))
    xbmcplugin.endOfDirectory(handle, cacheToDisc=False)


def run(handle, params):
    action = params.get('action')
    try:
        if action == 'vinyl_detail':
            from wcs.vinyl import detail
            detail.open_detail(params)
        elif action == 'vinyl_options':
            from wcs.vinyl import detail
            detail.options(params)
        elif action == 'vinyl_login':
            login()
        elif action == 'vinyl_logout':
            logout()
        elif action == 'vinyl_browse':
            browse(handle, params)
        elif action == 'vinyl_favorites':
            items = []
            for r in widgets.ROWS:
                if r.startswith('vinyl_favorite_'):
                    path = BASE + '?' + urlencode({'action': 'vinyl_browse', 'row': r})
                    items.append((path, xbmcgui.ListItem(client.addon().getLocalizedString(widgets.ROWS[r][2]), offscreen=True), True))
            xbmcplugin.addDirectoryItems(handle, items, len(items))
            xbmcplugin.endOfDirectory(handle)
        elif action == 'vinyl_item':
            click = params.get('click', 'open')
            if click == 'detail':
                from wcs.vinyl import detail
                detail.open_detail(params)
                return
            offset = _offset(params)
            paginated = params.get('kind') in ('album', 'artist', 'genre')
            if click == 'open' and paginated:
                songs, more = client.song_page(client.collection_path(
                    params['kind'], params.get('id', ''), params.get('name', ''), params.get('artist', '')), offset)
            else:
                songs = _songs(params)
            if click == 'open':
                parent, owner = '', False
                if params.get('kind') == 'playlist':
                    playlist = client.request('playlists/{}'.format(int(params['id'])))
                    parent, owner = params['id'], str(playlist.get('user_id')) == str(client.account())
                queue = ','.join(str(s['id']) for s in songs)
                entries = [dict(s, _queue=queue, _parent_playlist=parent, _owner=owner) for s in songs]
                items = [widgets.item(s, 'song', params.get('row', ''), 'play', listing=True) for s in entries]
                if paginated:
                    _pages(items, params, offset, more)
                xbmcplugin.setContent(handle, 'songs')
                xbmcplugin.addDirectoryItems(handle, items, len(items))
                xbmcplugin.endOfDirectory(handle, cacheToDisc=False)
            else:
                _play(songs, click)
        elif action == 'vinyl_context':
            from wcs.vinyl.context import run as context_action
            with widgets.defer_refresh():
                context_action(params)
    except Exception as exc:
        message = client.addon().getLocalizedString(32518 if isinstance(exc, client.LoginRequired) else 32532)
        xbmcgui.Dialog().notification('Vinyl', message, xbmcgui.NOTIFICATION_ERROR)
        xbmc.log('[Milionář Vinyl] {} failed: {}'.format(action, type(exc).__name__), xbmc.LOGWARNING)
        if handle >= 0:
            xbmcplugin.endOfDirectory(handle, succeeded=False)
