from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals

from __future__ import unicode_literals, absolute_import
# All the functionality to connect to SportTracks

# Python
import oauth2 as oauth
import cgi
import pytz
import requests
import requests.auth
import json
from django.utils import timezone
from datetime import datetime
from datetime import timedelta
import arrow
import numpy as np
from dateutil import parser
import time
from time import strftime

import rowers.dataprep as dataprep
import math
from math import sin,cos,atan2,sqrt
import os,sys
import urllib
import iso8601
from uuid import uuid4


# 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, make_cumvalues
import pandas as pd
from rowers.models import Rower,Workout,TombStone
import rowers.mytypes as mytypes
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
    )

from rowers.utils import (
    NoTokenError, custom_exception_handler, ewmovingaverage,
    geo_distance,uniqify
    )


# Splits SportTracks data which is one long sequence of
# [t,[lat,lon],t2,[lat2,lon2] ...]
# to [t,t2,t3, ...], [[lat,long],[lat2,long2],...
def splitstdata(lijst):
    t = []
    latlong = []
    while len(lijst)>=2:
        t.append(lijst[0])
        latlong.append(lijst[1])
        lijst = lijst[2:]

    return [np.array(t),np.array(latlong)]

def splituadata(lijst):
    t = []
    y = []
    for d in lijst:
        t.append(d[0])
        y.append(d[1])

    return np.array(t),np.array(y)

def imports_open(user,oauth_data):
    r = Rower.objects.get(user=user)
    token = getattr(r,oauth_data['tokenname'])
    try:
        refreshtoken = getattr(r,oauth_data['refreshtokenname'])
    except (TypeError,AttributeError,KeyError):
        refreshtoken = None

    try:
        tokenexpirydate = getattr(r,oauth_data['expirydatename'])
    except (TypeError,AttributeError,KeyError):
        tokenexpirydate = None

    if (token == '') or (token is None):
        s = "Token doesn't exist. Need to authorize"
        raise NoTokenError("User has no token")
    else:
        tokenname = oauth_data['tokenname']
        refreshtokenname = oauth_data['refreshtokenname']
        expirydatename = oauth_data['expirydatename']
        if tokenexpirydate and timezone.now()+timedelta(seconds=3599)>tokenexpirydate:
            token = imports_token_refresh(
                user,
                tokenname,
                refreshtokenname,
                expirydatename,
                oauth_data,
            )
        elif tokenexpirydate is None and expirydatename is not None and 'strava' in expirydatename:
            token = imports_token_refresh(
                user,
                tokenname,
                refreshtokenname,
                expirydatename,
                oauth_data,
                )


    return token


# Refresh token using refresh token
def imports_do_refresh_token(refreshtoken,oauth_data,access_token=''):
    client_auth = requests.auth.HTTPBasicAuth(
        oauth_data['client_id'],
        oauth_data['client_secret']
        )

    post_data = {"grant_type": "refresh_token",
                 "client_secret": oauth_data['client_secret'],
                 "client_id": oauth_data['client_id'],
                 "refresh_token": refreshtoken,
                 }
    headers = {'user-agent': 'sanderroosendaal',
               'Accept': 'application/json',
               'Content-Type': oauth_data['content_type']}

    # for Strava
    if 'grant_type' in oauth_data:
        if oauth_data['grant_type']:
            post_data['grant_type'] = oauth_data['grant_type']
        else:
            grant_type = post_data.pop('grant_type',None)

    if oauth_data['bearer_auth']:
        headers['authorization'] = 'Bearer %s' % access_token

    baseurl = oauth_data['base_url']

    if 'json' in oauth_data['content_type']:
        try:
            response = requests.post(baseurl,
                                 data=json.dumps(post_data),
                                 headers=headers)
        except:
            raise NoTokenError("Failed to get token")
    else:
        try:
            response = requests.post(baseurl,
            data=post_data,
            headers=headers
            )
        except:
            raise NoTokenError("Failed to get token")



    if response.status_code == 200 or response.status_code == 201:
        token_json = response.json()
    else:
        raise NoTokenError("User has no token")

    try:
        thetoken = token_json['access_token']
    except KeyError:
        raise NoTokenError("User has no token")

    try:
        expires_in = token_json['expires_in']
    except KeyError:
        try:
            expires_at = arrow.get(token_json['expires_at']).timestamp
            expires_in = expires_at - arrow.now().timestamp
        except KeyError:
            expires_in = 0
    try:
        refresh_token = token_json['refresh_token']
    except KeyError:
        refresh_token = refreshtoken
    try:
        expires_in = int(expires_in)
    except (TypeError,ValueError):
        expires_in = 0


    return [thetoken,expires_in,refresh_token]

# Exchange ST access code for long-lived ST access token
def imports_get_token(
        code,oauth_data
        ):

    redirect_uri = oauth_data['redirect_uri']
    client_secret = oauth_data['client_secret']
    client_id = oauth_data['client_id']
    base_uri = oauth_data['base_url']


    client_auth = requests.auth.HTTPBasicAuth(
        client_id,client_secret
        )


    post_data = {"grant_type": "authorization_code",
                 "code": code,
                 "redirect_uri": redirect_uri,
                 "client_secret": client_secret,
                 "client_id": client_id,
                 }

    try:
        headers = oauth_data['headers']
    except KeyError:
        headers = {'Accept': 'application/json',
                   'Api-Key': client_id,
                   'Content-Type': 'application/json',
                   'user-agent': 'sanderroosendaal'}

    if 'grant_type' in oauth_data:
        if oauth_data['grant_type']:
            post_data['grant_type'] = oauth_data['grant_type']
            if 'strava' in oauth_data['autorization_uri']:
                post_data['grant_type'] = "authorization_code"
        else:
            grant_type = post_data.pop('grant_type',None)


    if 'json' in oauth_data['content_type']:
        response = requests.post(
            base_uri,
            data=json.dumps(post_data),
            headers=headers)
    else:
        response = requests.post(
            base_uri,
            data=post_data,
            headers=headers)

    if response.status_code == 200 or response.status_code == 201:
        token_json = response.json()
        try:
            thetoken = token_json['access_token']
        except KeyError:
            return [0,0,0]
        try:
            refresh_token = token_json['refresh_token']
        except KeyError:
            refresh_token = ''
        try:
            expires_in = token_json['expires_in']
        except KeyError:
            expires_in = 0
        try:
            expires_in = int(expires_in)
        except (ValueError,TypeError):
            expires_in = 0
    else:
        return [0,0,0]


    return [thetoken,expires_in,refresh_token]

# Make authorization URL including random string
def imports_make_authorization_url(oauth_data):
    # Generate a random string for the state parameter
    # Save it for use later to prevent xsrf attacks

    state = str(uuid4())

    params = {"client_id": oauth_data['client_id'],
              "response_type": "code",
              "redirect_uri": oauth_data['redirect_uri'],
              "scope":oauth_data['scope'],
              "state":state}


    import urllib
    url = oauth_data['authorizaton_uri']+urllib.parse.urlencode(params)

    return HttpResponseRedirect(url)

# This is token refresh. Looks for tokens in our database, then refreshes
def imports_token_refresh(user,tokenname,refreshtokenname,expirydatename,oauth_data):
    r = Rower.objects.get(user=user)

    refreshtoken = getattr(r,refreshtokenname)

    # for Strava transition
    if not refreshtoken:
        refreshtoken = getattr(r,tokenname)


    res = imports_do_refresh_token(refreshtoken,oauth_data)
    access_token = res[0]
    expires_in = res[1]
    refresh_token = res[2]
    expirydatetime = timezone.now()+timedelta(seconds=expires_in)

    setattr(r,tokenname,access_token)
    if expirydatename is not None:
        setattr(r,expirydatename,expirydatetime)
    if refreshtokenname is not None:
        setattr(r,refreshtokenname,refresh_token)

    r.save()
    return access_token
