# -*- coding: utf-8 -*-
"""Vinyl context actions; all REST calls use client.request and the hosting proxy."""
from urllib.parse import quote, urlencode

import xbmc
import xbmcgui

from wcs.skin.context import LABELS, builtin, text
from wcs.vinyl import client


def owns(identity):
    return any(str(p['id']) == str(identity) for p in client.cached('playlists'))


def favorite(data):
    kind = data['kind']
    if kind == 'song':
        # Missing from a bounded favorites page never proves non-membership.
        session = client.scope()
        recent = client.favorite_state(data['id'])
        if recent is not None and recent.get('state') is not None:
            return recent['state']
        if recent is None:
            snapshot = client.snapshot('songs') or {'items': []}
            collections = [snapshot['items']] + list(snapshot.get('sorts', {}).values())
            for entries in collections:
                for song in entries:
                    if str(song.get('id')) == str(data['id']):
                        value = client.favorite_value(song.get('is_favorite'))
                        if value is not None:
                            return value
            value = client.favorite_value(data.get('is_favorite'))
            if value is not None:
                return value
            if any(str(song.get('id')) == str(data['id']) for song in client.cached('favorite_songs')):
                return True
        else:
            # Failed lookups are cached too, so repeated opens do not keep blocking.
            if recent.get('failed'):
                return None
        try:
            # Existing playback detail route (actions._songs); no source enumeration.
            song = client.request('songs/{}'.format(int(data['id'])), timeout=(2, 3))
        except Exception:
            client.remember_favorite(data['id'], None, session, failed=True)
            return None
        if client.scope() != session or not isinstance(song, dict):
            return None
        value = client.favorite_value(song.get('is_favorite'))
        client.remember_favorite(data['id'], value, session, failed=value is None)
        return value
    source = {'playlist': 'playlists', 'album': 'albums', 'artist': 'artists'}.get(kind)
    if not source:
        return False
    value = client.favorite_value(data.get('is_favorite'))
    if value is not None:
        return value
    for collection in (source, 'favorite_' + source):
        for entry in client.cached(collection):
            if kind == 'artist':
                match = entry.get('name') == data.get('name')
            else:
                match = str((entry.get('album_id') or entry.get('id')) if kind == 'album' else entry.get('id')) == str(data.get('id'))
                if kind == 'album' and not entry.get('album_id') and not entry.get('id'):
                    match = entry.get('name') == data.get('name') and (entry.get('primary_artist') or '') == data.get('artist', '')
            if match:
                if collection.startswith('favorite_'):
                    return True
                value = client.favorite_value(entry.get('is_favorite'))
                if value is not None:
                    return value
    return None


def can(action, data):
    """Whether the item can have the action, from the item and the cache only (hero buttons, widget fast path)."""
    kind, account = data.get('kind'), bool(client.account())
    if kind == 'song':
        return (action in ('play', 'queue') or (action == 'play_from' and bool(data.get('ids')))
                or (account and action in ('favorite', 'add_playlist', 'create_playlist'))
                or (action in ('album', 'artist') and bool(data.get(action))))
    if action in ('open', 'play_all', 'queue'):
        return True
    if action == 'shuffle':
        return kind != 'radio'
    if action == 'favorite':
        return account and kind in ('playlist', 'album', 'artist')
    if action == 'create_playlist':
        return account
    return action in ('rename_playlist', 'delete_playlist') and account and kind == 'playlist' and owns(data.get('id'))


def actions(data):
    kind = data['kind']
    result = {}
    values = {k: v for k, v in data.items() if k in ('kind', 'id', 'name', 'artist', 'row', 'ids', 'ctx', 'parent_playlist', 'owner')}
    play = ('play', 'queue', 'play_from') if kind == 'song' else ('open', 'play_all', 'queue') + (() if kind == 'radio' else ('shuffle',))
    for action in play:
        if action == 'play_from' and not data.get('ids'):
            continue
        result[action] = (text(32526 if action == 'play' else 32521 if action == 'open' else LABELS[action]),
                          builtin(dict(values, action='vinyl_item', click=action), folder=action == 'open', music=True))
    if client.account():
        if kind in ('song', 'playlist', 'album', 'artist'):
            state = favorite(data)
            if state is not None or kind != 'song':
                label = text(32613 if state else 32612) if state is not None else xbmc.getLocalizedString(10134)
                result['favorite'] = (label, builtin(dict(values, action='vinyl_context', op='favorite')))
        if kind == 'song':
            result['add_playlist'] = (text(32614), builtin(dict(values, action='vinyl_context', op='add_playlist')))
        result['create_playlist'] = (text(32615), builtin(dict(values, action='vinyl_context', op='create_playlist')))
        if kind == 'playlist' and owns(data.get('id')):
            for action in ('rename_playlist', 'delete_playlist'):
                result[action] = (text(LABELS[action]), builtin(dict(values, action='vinyl_context', op=action)))
        if kind == 'song' and data.get('parent_playlist') and data.get('owner') == '1':
            options = ['remove_song']
            ids = data.get('ids', '').split(',')
            if str(data.get('id')) in ids:
                index = ids.index(str(data['id']))
                if index > 0:
                    options.append('song_up')
                if index < len(ids) - 1:
                    options.append('song_down')
            for action in options:
                result[action] = (text(LABELS[action]), builtin(dict(values, action='vinyl_context', op=action)))
    if kind == 'song':
        song = next((s for s in client.cached('songs') if str(s['id']) == str(data.get('id'))), data)
        if song.get('album'):
            result['album'] = (text(32619), builtin(dict(kind='album', id=song.get('album_id', ''), name=song['album'],
                                                       artist=song.get('artist', ''), action='vinyl_item', click='open'), folder=True, music=True))
        if song.get('artist'):
            result['artist'] = (text(32620), builtin(dict(kind='artist', name=song['artist'], action='vinyl_item', click='open'), folder=True, music=True))
    return result


def _owned_playlist(identity):
    data = client.request('playlists/{}'.format(int(identity)))
    if str(data.get('user_id')) != str(client.account()):
        raise PermissionError('Playlist is not owned by this account')
    return data


def _create():
    name = xbmcgui.Dialog().input(text(32615)).strip()
    if not name:
        return None
    return client.request('playlists', 'POST', {'name': name})


def run(params):
    if not client.account():
        raise client.LoginRequired()
    op, kind = params.get('op'), params.get('kind')
    identity = params.get('id')
    changed = False
    if op == 'favorite':
        if kind in ('song', 'playlist'):
            path = '{}s/{}/favorite'.format(kind, int(identity))
        elif kind == 'album':
            path = 'browse/albums/{}/favorite?{}'.format(quote(params['name'], safe=''), urlencode(
                {'albumId': identity or '', 'artist': params.get('artist', '')}))
        elif kind == 'artist':
            path = 'browse/artists/favorite?' + urlencode({'artist': params['name']})
        else:
            return
        client.request(path, 'PATCH')
        changed = True
    elif op == 'create_playlist':
        changed = bool(_create())
    elif op == 'add_playlist':
        playlists = [p for p in client.request('playlists')['playlists'] if p.get('is_owner')]
        picked = xbmcgui.Dialog().select(text(32614), [p['name'] for p in playlists] + [text(32615)])
        if picked < 0:
            return
        playlist = _create() if picked == len(playlists) else playlists[picked]
        if not playlist:
            return
        _owned_playlist(playlist['id'])
        existing = client.collection('playlist', playlist['id'])
        if any(str(s['id']) == str(identity) for s in existing):
            xbmcgui.Dialog().notification('Vinyl', text(32630))
            return
        client.request('playlists/{}/songs'.format(int(playlist['id'])), 'POST', {'song_id': int(identity)})
        changed = True
    elif op in ('rename_playlist', 'delete_playlist'):
        playlist = _owned_playlist(identity)
        if op == 'rename_playlist':
            name = xbmcgui.Dialog().input(text(32616), playlist['name']).strip()
            if name and name != playlist['name']:
                client.request('playlists/{}'.format(int(identity)), 'PATCH', {'name': name})
                changed = True
        elif xbmcgui.Dialog().yesno(text(32617), text(32631).format(playlist['name'])):
            # Delete the playlist only, never its library songs/files.
            client.request('playlists/{}'.format(int(identity)), 'DELETE')
            changed = True
    elif op in ('remove_song', 'song_up', 'song_down'):
        parent = int(params['parent_playlist'])
        playlist = _owned_playlist(parent)
        if op == 'remove_song':
            if xbmcgui.Dialog().yesno(text(32618), text(32632).format(params.get('name', ''), playlist['name'])):
                client.request('playlists/{}/songs/{}'.format(parent, int(identity)), 'DELETE')
                changed = True
        else:
            ids = [int(s['id']) for s in playlist.get('songs', [])]
            index = ids.index(int(identity))
            target = index + (-1 if op == 'song_up' else 1)
            if 0 <= target < len(ids):
                ids[index], ids[target] = ids[target], ids[index]
                client.request('playlists/{}/reorder'.format(parent), 'PATCH', {'song_ids': ids})
                changed = True
    if changed:
        # Refresh once after a deliberate edit, then redraw favorites/ownership/menu labels from the updated cache.
        from wcs.vinyl import widgets
        try:
            widgets.refresh()
        except Exception:
            from wcs.vinyl.actions import refresh_soon
            refresh_soon()
        xbmc.executebuiltin('Container.Refresh')
        xbmcgui.Dialog().notification('Vinyl', text(32633))
    return changed
