import spotipy
from sklearn.manifold import TSNE
from numpy import array
from sklearn.ensemble import IsolationForest

def get_playlists(access_token):
	sp = spotipy.client.Spotify(auth=access_token)
	return sp.current_user_playlists()['items']

def get_song_features(access_token, playlist_id):
	sp = spotipy.client.Spotify(auth=access_token)
	user_id = sp.me()['id']
	playlist = sp.user_playlist(user_id, playlist_id)
	num_tracks = playlist['tracks']['total']
	num_tracks_so_far = 0
	tracks = []
	while num_tracks_so_far < num_tracks:
		tracks += sp.user_playlist_tracks(user_id, playlist_id=playlist_id, offset=num_tracks_so_far)['items']
		num_tracks_so_far += 100
	ids, artists, titles =  [], [], []
	for track in tracks:
		ids.append(track['track']['id'])
		artists.append(track['track']['artists'][0]['name'])
		titles.append(track['track']['name'])
	features = get_audio_features(ids, sp)
	none_idx = [i for i, item in enumerate(features) if item is None]
	for i in sorted(none_idx, reverse=True):
		del features[i]
		del artists[i]
		del titles[i]
		del ids[i]
	return artists, titles, features, playlist['name'], ids
def get_audio_features(tracks, sp):
	num_tracks = len(tracks)
	num_extracted = 0
	feature_dict = []
	while num_extracted < num_tracks:
		if (num_tracks - num_extracted) // 50 > 0:
			feature_dict += sp.audio_features(tracks[num_extracted:num_extracted + 50])
			num_extracted += 50
		else:
			feature_dict += sp.audio_features(tracks[num_extracted:])
			num_extracted = num_tracks
	return feature_dict

def get_projection(access_token, playlist_id, features=['danceability', 'acousticness', 'energy', 'instrumentalness', 'valence']):
	artists, titles, data, playlist_name, ids = get_song_features(access_token, playlist_id)
	feature_table = []
	for i in range(len(data)):
		feature_table.append([data[i][k] for k in features])
	projection = TSNE(n_components=2, init='pca').fit_transform(array(feature_table))
	prediction = IsolationForest(behaviour='new', contamination=0.1, random_state=42).fit_predict(projection)
	outlier_idx =  [i for i, item in enumerate(prediction) if item == -1]
	outlier_artist = [artists[i] for i in outlier_idx]
	outlier_titles = [titles[i] for i in outlier_idx]
	outlier_ids = [ids[i] for i in outlier_idx]
	return list(projection[:,0]), list(projection[:,1]), titles, artists, playlist_name, ids, zip(outlier_artist, outlier_titles, outlier_ids)

