#!/usr/bin/env python
import requests
import simplejson as json
import argparse
import csv
from pathlib import Path

requests.adapters.DEFAULT_RETRIES = 5

parser = argparse.ArgumentParser(description='Fetches an album from spotify and transforms its data into a 1-dimension matrix.')
parser.add_argument('-m', action='store_true', help='Output value matrix in format:[avg acousticness] [avg danceability] [avg duration] [avg energy] [avg instrumentalness] [most frequest key] [record label (mapping in code)] [avg liveness] [avg loudness] [most frequent mode] [popularity] [release year] [avg speechiness] [avg tempo] [most frequent time_signature] [avg valence]')
parser.add_argument('-m1', help="Avg change between averages")
parser.add_argument('-m2', help="2D matrix where each value is values of a best fit equation")
parser.add_argument('--api-key', help='Spotify API key:\https://developer.spotify.com/console/get-album-tracks/')
parser.add_argument('--artist', help='Artist name')
parser.add_argument('--album', help='Album name')
parser.add_argument('--input', help='Input file name in format [album] [artist]')
parser.add_argument('--output', help='Output filename')

args = parser.parse_args()
apikey = args.api_key
artistName = args.artist
albumName = args.album
outputMatrix = args.m
filename = args.input
outfilename = args.output

numProcessed = 0
total = 17411

def apiLink():
	print "https://accounts.spotify.com/authorize?client_id=500403bfc1ab4026a50f88bb0366066e&redirect_uri=https://seattlelofts.design/callback&scope=user-read-private%20user-read-email&response_type=token&state=123"

if apikey == None:
	apiLink();
	exit();

def getAuthHeader():
	return {'Authorization': "Bearer " + apikey}

def checkResponseStatus(response):
	# TODO make request logic common and use proper exception handling:
	# https://stackoverflow.com/questions/16511337/correct-way-to-try-except-using-python-requests-module
	if "200" not in str(response.status_code):
		print "Request failed with:" + response.text
		print "Exiting."
		apiLink();
		exit();

def getAlbumId(artist, album):
	url = 'https://api.spotify.com/v1/search'
	query = "album:" + album + " artist:" + artist
	payload = {'q': query, 'type': 'album', 'limit': 1}
	auth = getAuthHeader()
	response = requests.get(url, params=payload, headers=auth)
	if "502" in str(response.status_code):
		print "Retrying request"
		response = requests.get(url, params=payload, headers=auth)

	checkResponseStatus(response)
	responseJson = json.loads(response.text)
	if not responseJson['albums']['items']:
		print "[NOT FOUND][album:" + album + " artist:" + artist + "]"
		return ""
	else:
		return responseJson['albums']['items'][0]['id']

def getReleaseYear(releaseDate):
	# returns first 4 characters of 
	# spotify release date yyyy-mm-dd
	return releaseDate[:4]

def getAlbumRequest(albumid):
	url = "https://api.spotify.com/v1/albums/" + albumid
	auth = getAuthHeader()
	response = requests.get(url, headers=auth)
	responseJson = json.loads(response.text)
	return responseJson

def getAlbumInfo(albumInfo):
	return {
		'label': albumInfo['label'], 
		'popularity': albumInfo['popularity'], 
		'releaseDate': getReleaseYear(albumInfo['release_date'])
	}

def getAlbumTrackIds(albumInfo):
	trackIds = []
	for track in albumInfo['tracks']['items']:
		trackIds.append(track['id'])
	return trackIds

def getTrackFeatures(trackIds):
	url = "https://api.spotify.com/v1/audio-features"
	auth = getAuthHeader()
	ids = ",".join(trackIds)
	payload = {'ids': ids}
	response = requests.get(url, params=payload, headers=auth)
	responseJson = json.loads(response.text)
	trackFeatures = [];
	for track in responseJson['audio_features']:
		if not track:
			print "[NOT FOUND][Album Missing Tracks]"
			return
		features = {'energy': track['energy'], 'liveness': track['liveness'], 'tempo': track['tempo'], 'speechiness': track['speechiness'], 'acousticness': track['acousticness'], 'instrumentalness': track['instrumentalness'], 'time_signature': track['time_signature'], 'danceability': track['danceability'], 'key': track['key'], 'duration_ms': track['duration_ms'], 'loudness': track['loudness'], 'valence': track['valence'], 'mode': track['mode']}
		trackFeatures.append(features)
	return trackFeatures

def merge_two_dicts(albumInfo, tracks):
	for track in tracks:
		track.update(albumInfo)
	return tracks

def printMatrix(artist,album,score,tracks):
	file = open(outfilename, 'a+')
	for track in tracks:
		matrix = "%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n" % (artist, album, score, track['acousticness'], track['danceability'], track['duration_ms'], track['energy'], track['instrumentalness'], track['key'], track['label'], track['liveness'], track['loudness'], track['mode'], track['popularity'], track['releaseDate'], track['speechiness'], track['tempo'], track['time_signature'], track['valence'])	
		file.write(matrix.encode('utf-8'))
	file.close()

def printPretty(features):
	keys = features.keys()
	keys.sort()
	for key in keys:
		print key + ": " + str(features[key]) 

def getMatrix(artistName, albumName, score):
	albumid = getAlbumId(artistName, albumName)
	if not albumid:
		print("Skipped:" + artistName + "," + albumName)
		return
	getAlbumResponse = getAlbumRequest(albumid)
	albuminfo = getAlbumInfo(getAlbumResponse)

	if not outputMatrix:
		print "Album Found: " + getAlbumResponse['name'] + " - " + getAlbumResponse['artists'][0]['name']

	trackids = getAlbumTrackIds(getAlbumResponse)
	tracks = getTrackFeatures(trackids)
	if not tracks:
		return
	mergedFeatures = merge_two_dicts(albuminfo, tracks)
	printMatrix(artistName, albumName, score, tracks)

labels = "artist,album,score,acousticness,danceability,duration,energy,instrumentalness,key,label,liveness,loudness,mode,popularity,release year,speechiness,tempo,time_signature,valence"
if filename != None:
	mycsv = csv.reader(open(filename))
	for row in mycsv:
		getMatrix(row[1], row[0], row[2])
		numProcessed += 1
		print "["+str(numProcessed)+"/"+str(total)+"]"
else:
	getMatrix(artistName, albumName)






