
import spotipy
from random import shuffle

import utils

def playlistCommand(args, config):

    splits = args.split(' ', 1)
    cmd = splits[0]

    if cmd == 'list':
        listUserPlaylists(config)
    elif cmd == 'sort':
        modifyPlaylist(splits[1], config, shuffle=False)
    elif cmd == 'shuffle':
        modifyPlaylist(splits[1], config, shuffle=True)
    else:
        print 'Error {0} invalid command'.format(cmd)

def listUserPlaylists(config):

    token = utils.getUserToken(config)
    spot = spotipy.Spotify(auth=token)
    playlists = spot.user_playlists(config['username'])

    for playlist in playlists['items']:
        print playlist['name']

def modifyPlaylist(args, config, shuffle=False):

    splits = args.split(' ', 1)
    if len(splits) > 2:
        print 'Error, Please provide: playlist sort [key] [playlist]'
        return
    key, name = splits[0], splits[1]
    if (not key == 'album') and (not key == 'artist'):
        print 'Error, invalid key. Only supported keys are [album, artist]'
        return

    token = utils.getUserToken(config)
    spot = spotipy.Spotify(auth=token)

    playlists = readPlaylists(spot, config)
    playlistId = findPlaylist(playlists, name)
    if playlistId == None:
        print 'Error, invalid playlist name {0}'.format(name)
        return

    tracks = readTracks(spot, config, playlistId)
    newTracks = sortTracks(tracks, key)

    if shuffle:
        newTracks = shuffleTracks(newTracks, key)

    cmd = 'shuffle' if shuffle else 'sort'
    newName = name+'-'+cmd+'-'+key
    replaceTracks(newName, playlists, newTracks, spot, config)


def readPlaylists(spot, config):
    playlists = []
    cur = 0
    while True:
        pager = spot.user_playlists(config['username'], offset=cur)
        for item in pager['items']:
            playlist = {}
            playlist['name'] = item['name']
            playlist['id'] = item['id']
            playlists.append(playlist)
        cur += len(pager['items'])
        if cur >= pager['total']:
            break
    return playlists

def readTracks(spot, config, playlistId):
    cur = 0
    songs = []
    while True:
        tracks = spot.user_playlist_tracks(config['username'], playlistId, offset=cur)
        for track in tracks['items']:
            song = {}
            song['name'] = track['track']['name']
            song['artist'] = track['track']['artists'][0]['name']
            song['album'] = track['track']['album']['name']
            song['disc_number'] = track['track']['disc_number']
            song['track_number'] = track['track']['track_number']
            song['id'] = track['track']['id']
            songs.append(song)
        cur += len(tracks['items'])
        if cur == tracks['total']:
            break
    return songs

def replaceTracks(name, playlists, tracks, spot, config):
    track_ids = map(lambda x: x['id'], tracks)
    newId = findPlaylist(playlists, name)
    cur = 0
    if newId == None:
        newId = spot.user_playlist_create(config['username'], name,public=False)['id']
    else:
        spot.user_playlist_replace_tracks(config['username'], newId, track_ids[cur:min(cur+100,len(track_ids))])
        cur += min(cur+100,len(track_ids))

    while cur < len(track_ids):
        spot.user_playlist_add_tracks(config['username'], newId, track_ids[cur:min(cur+100,len(track_ids))])
        cur += 100

def sortTracks(tracks, key):

    tracks.sort(key=lambda x: x['track_number'])
    tracks.sort(key=lambda x: x['disc_number'])
    tracks.sort(key=lambda x: x['album'])
    if key == 'artist':
        tracks.sort(key=lambda x: x['artist'].lower())
    return tracks

def shuffleTracks(tracks, key):
    bins = {}
    for track in tracks:
        if track[key] not in bins.keys():
            bins[track[key]] = []
        bins[track[key]].append(track)
    newOrder = bins.keys()
    shuffle(newOrder)
    finalOrder = []
    for k in newOrder:
        finalOrder += bins[k]
    return finalOrder

def findPlaylist(playlists, name):
    playlistId = None
    for playlist in playlists:
        if playlist['name'] == name:
            playlistId = playlist['id']
    return playlistId
