# All the functionality to connect to SportTracks

# Python
import oauth2 as oauth
import cgi
import requests
import requests.auth
import json
from django.utils import timezone
from datetime import datetime
import numpy as np
from dateutil import parser
import time
import math
from math import sin,cos,atan2,sqrt

import urllib
import c2stuff

# Django
from django.shortcuts import render_to_response
from django.http import HttpResponseRedirect, HttpResponse,JsonResponse
from django.conf import settings
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.models import User
from django.contrib.auth.decorators import login_required

# Project
# from .models import Profile
from rowingdata import rowingdata
import pandas as pd
from rowers.models import Rower,Workout,checkworkoutuser

from rowsandall_app.settings import C2_CLIENT_ID, C2_REDIRECT_URI, C2_CLIENT_SECRET, STRAVA_CLIENT_ID, STRAVA_REDIRECT_URI, STRAVA_CLIENT_SECRET, SPORTTRACKS_CLIENT_SECRET, SPORTTRACKS_CLIENT_ID, SPORTTRACKS_REDIRECT_URI

# Custom error class - to raise a NoTokenError
class SportTracksNoTokenError(Exception):
    def __init__(self,value):
	self.value=value

    def __str__(self):
	return repr(self.value)


# Custom exception handler, returns a 401 HTTP message
# with exception details in the json data
def custom_exception_handler(exc,message):

    response = {
	"errors": [
	    {
		"code": str(exc),
		"detail": message,
		}
	    ]
	}

    res = HttpResponse(message)
    res.status_code = 401
    res.json = json.dumps(response)

    return res

# Checks if user has SportTracks token, renews them if they are expired
def sporttracks_open(user):
    r = Rower.objects.get(user=user)
    if (r.sporttrackstoken == '') or (r.sporttrackstoken is None):
	s = "Token doesn't exist. Need to authorize"
	raise SportTracksNoTokenError("User has no token")
    else:
	if (timezone.now()>r.sporttrackstokenexpirydate):
	    thetoken = sporttracksstuff.rower_sporttracks_token_refresh(user)
	else:
	    thetoken = r.sporttrackstoken

    return thetoken


# Refresh ST token using refresh token
def do_refresh_token(refreshtoken):
    client_auth = requests.auth.HTTPBasicAuth(SPORTTRACKS_CLIENT_ID, SPORTTRACKS_CLIENT_SECRET)
    post_data = {"grant_type": "refresh_token",
		 "client_secret": SPORTTRACKS_CLIENT_SECRET,
		 "client_id":SPORTTRACKS_CLIENT_ID,
		 "refresh_token": refreshtoken,
		 }
    headers = {'user-agent': 'sanderroosendaal',
	       'Accept': 'application/json',
	       'Content-Type': 'application/json'}

    url = "https://api.sporttracks.mobi/oauth2/token"
    
    response = requests.post(url,
                             data=json.dumps(post_data),
			     headers=headers)

    token_json = response.json()
    thetoken = token_json['access_token']
    expires_in = token_json['expires_in']
    try:
	refresh_token = token_json['refresh_token']
    except KeyError:
	refresh_token = refreshtoken

    return [thetoken,expires_in,refresh_token]

# Exchange ST access code for long-lived ST access token
def get_token(code):
    client_auth = requests.auth.HTTPBasicAuth(SPORTTRACKS_CLIENT_ID, SPORTTRACKS_CLIENT_SECRET)
    post_data = {"grant_type": "authorization_code",
                 "code": code,
                 "redirect_uri": SPORTTRACKS_REDIRECT_URI,
		 "client_secret": SPORTTRACKS_CLIENT_SECRET,
		 "client_id":SPORTTRACKS_CLIENT_ID,	     
		 }
    headers = {'Accept': 'application/json',
	       'Content-Type': 'application/json'}

    url = "https://api.sporttracks.mobi/oauth2/token"
    
    
    response = requests.post(url,
                             data=json.dumps(post_data),
			     headers=headers)
    if response.status_code == 200 or response.status_code == 201:
        token_json = response.json()
        thetoken = token_json['access_token']
        expires_in = token_json['expires_in']
        try:
	    refresh_token = token_json['refresh_token']
        except KeyError:
	    refresh_token = refreshtoken
    else:
        return [0,0,0]

    
    return [thetoken,expires_in,refresh_token]

# Make authorization URL including random string
def make_authorization_url(request):
    # Generate a random string for the state parameter
    # Save it for use later to prevent xsrf attacks
    from uuid import uuid4
    state = str(uuid4())

    params = {"client_id": SPORTTRACKS_CLIENT_ID,
              "response_type": "code",
              "redirect_uri": SPORTTRACKS_REDIRECT_URI,
	      "scope":"write",
	      "state":state}


    import urllib
    url = "https://api.sporttracks.mobi/oauth2/authorize" +urllib.urlencode(params)

    return HttpResponseRedirect(url)

# This is token refresh. Looks for tokens in our database, then refreshes
def rower_sporttracks_token_refresh(user):
    r = Rower.objects.get(user=user)
    res = do_refresh_token(r.sporttracksrefreshtoken)
    access_token = res[0]
    expires_in = res[1]
    refresh_token = res[2]
    expirydatetime = timezone.now()+timedelta(seconds=expires_in)

    r = Rower.objects.get(user=user)
    r.sporttrackstoken = access_token
    r.tokenexpirydate = expirydatetime
    r.sporttracksrefreshtoken = refresh_token

    r.save()
    return r.sporttrackstoken

# Get list of workouts available on SportTracks
def get_sporttracks_workout_list(user):
    r = Rower.objects.get(user=user)
    if (r.sporttrackstoken == '') or (r.sporttrackstoken is None):
	s = "Token doesn't exist. Need to authorize"
	return custom_exception_handler(401,s)
    elif (timezone.now()>r.sporttrackstokenexpirydate):
	s = "Token expired. Needs to refresh."
	return custom_exception_handler(401,s)
    else:
	# ready to fetch. Hurray
	authorizationstring = str('Bearer ' + r.sporttrackstoken)
	headers = {'Authorization': authorizationstring,
		   'user-agent': 'sanderroosendaal',
		   'Content-Type': 'application/json'}
	url = "https://api.sporttracks.mobi/api/v2/fitnessActivities"
	s = requests.get(url,headers=headers)

    return s

# Get workout summary data by SportTracks ID
def get_sporttracks_workout(user,sporttracksid):
    r = Rower.objects.get(user=user)
    if (r.sporttrackstoken == '') or (r.sporttrackstoken is None):
	return custom_exception_handler(401,s)
	s = "Token doesn't exist. Need to authorize"
    elif (timezone.now()>r.sporttrackstokenexpirydate):
	s = "Token expired. Needs to refresh."
	return custom_exception_handler(401,s)
    else:
	# ready to fetch. Hurray
	authorizationstring = str('Bearer ' + r.sporttrackstoken)
	headers = {'Authorization': authorizationstring,
		   'user-agent': 'sanderroosendaal',
		   'Content-Type': 'application/json'}
	url = "https://api.sporttracks.mobi/api/v2/fitnessActivities/"+str(sporttracksid)
	s = requests.get(url,headers=headers)

    return s

# Create Workout Data for upload to SportTracks
def createsporttracksworkoutdata(w):
    filename = w.csvfilename
    try:
        row = rowingdata(filename)
    except:
        return 0
    
    averagehr = int(row.df[' HRCur (bpm)'].mean())
    maxhr = int(row.df[' HRCur (bpm)'].max())
    duration = w.duration.hour*3600
    duration += w.duration.minute*60
    duration += w.duration.second
    duration += +1.0e-6*w.duration.microsecond

    # adding diff, trying to see if this is valid
    #t = row.df.ix[:,'TimeStamp (sec)'].values-10*row.df.ix[0,'TimeStamp (sec)']
    t = row.df.ix[:,'TimeStamp (sec)'].values-row.df.ix[0,'TimeStamp (sec)']
    t[0] = t[1]

    d = row.df.ix[:,'cum_dist'].values
    d[0] = d[1]
    t = t.astype(int)
    d = d.astype(int)
    spm = row.df[' Cadence (stokes/min)'].astype(int)
    spm[0] = spm[1]
    hr = row.df[' HRCur (bpm)'].astype(int)
    
    haslatlon=1
    
    try:
	lat = row.df[' latitude'].values
	lon = row.df[' longitude'].values
        if not lat.std() and not lon.std():
            haslatlon = 0
    except KeyError:
	haslatlon = 0

        
    haspower = 1
    try:
	power = row.df[' Power (watts)'].values
    except KeyError:
	haspower = 0

    locdata = []
    hrdata =  []
    spmdata = []
    distancedata = []
    powerdata = []

    for i in range(len(t)):
	hrdata.append(t[i])
	hrdata.append(hr[i])
	distancedata.append(t[i])
	distancedata.append(d[i])
	spmdata.append(t[i])
	spmdata.append(spm[i])
	if haslatlon:
	    locdata.append(t[i])
	    locdata.append([lat[i],lon[i]])
	if haspower:
	    powerdata.append(t[i])
	    powerdata.append(power[i])


    try:
        w.notes = w.notes+'\n from '+w.workoutsource+' via rowsandall.com'
    except TypeError:
        w.notes = 'from '+w.workoutsource+' via rowsandall.com'
        
    if haslatlon:
	data = {
	    "type": "Rowing",
	    "name": w.name,
#	    "start_time": str(w.date)+"T"+str(w.starttime)+"Z",
	    "start_time": w.startdatetime.isoformat(),
	    "total_distance": int(w.distance),
	    "duration": duration,
	    "notes": w.notes,
	    "avg_heartrate": averagehr,
	    "max_heartrate": maxhr,
	    "location": locdata,
	    "distance": distancedata,
	    "cadence": spmdata,
	    "heartrate": hrdata,
	    }
    else:
	data = {
	    "type": "Rowing",
	    "name": w.name,
#	    "start_time": str(w.date)+"T"+str(w.starttime)+"Z",
	    "start_time": w.startdatetime.isoformat(),
	    "total_distance": int(w.distance),
	    "duration": duration,
	    "notes": w.notes,
	    "avg_heartrate": averagehr,
	    "max_heartrate": maxhr,
	    "distance": distancedata,
	    "cadence": spmdata,
	    "heartrate": hrdata,
	    }

    if haspower:
	data['power'] = powerdata

    return data

# Obtain SportTracks Workout ID from the response returned on successful
# upload
def getidfromresponse(response):
    t = json.loads(response.text)
    uri = t['uris'][0]
    id = uri[len(uri)-13:len(uri)-5]
    
    return int(id)

    
def workout_sporttracks_upload(user,w):
    message = "Uploading to SportTracks"
    stid = 0
    # ready to upload. Hurray
    r = w.user

    thetoken = sporttracks_open(user)

    if (checkworkoutuser(user,w)):
	data = createsporttracksworkoutdata(w)
        if not data:
            message = "Data error"
            stid = 0
            return message,stid
        
	authorizationstring = str('Bearer ' + thetoken)
	headers = {'Authorization': authorizationstring,
		   'user-agent': 'sanderroosendaal',
		   'Content-Type': 'application/json'}

	url = "https://api.sporttracks.mobi/api/v2/fitnessActivities.json"
	response = requests.post(url,headers=headers,data=json.dumps(data))

	# check for duplicate error first
	if (response.status_code == 409 ):
	    message = "Duplicate error"
	    w.uploadedtosporttracks = -1
            stid = -1
	    w.save()
            return message, stid
	elif (response.status_code == 201 or response.status_code==200):
	    s= json.loads(response.text)
	    stid = getidfromresponse(response)
	    w.uploadedtosporttracks = stid
	    w.save()
            return 'Successfully synced to SportTracks',stid
	else:
	    s = response
	    message = "Something went wrong in workout_sporttracks_upload_view: %s" % s.reason
            stid = 0
            return message,stid
		
    else:
	message = "You are not authorized to upload this workout"
        stid = 0
        return message,stid

    return message,stid
