#!/usr/bin/python3
import sys
from pprint import pprint
import json
import time
import requests
import hashlib
import hmac
from urllib.parse import quote

#set params for API
#For API "Account type" we don't need username and password.
#Make sure u have set correct permissions for both the  "Account type" and "User Type" API's

token  = "BYU4Xhbm7N534eFUgOTGLJFj+FfhsG5GgRmwn/gKRFs"

p = {
  'secret'  : 'nSZj5oSGiTrVd/6DnI0e8DOVGmd25DbTaxPwKbksBPw', 
  'host'    : "rest.luxsci.com", 
  'debug'   : 1,
  'user'    : 'admin@apidev.trial6.luxsci.net',
  'pass'    : 'svn8tt3?xW'
}

new_username = "Ashish Bist"
new_password = "svn8tt3?xW"


#API Access Methods

'''res = Auth_Request(p);

p:
   token:  Required. API Token
   secret: Required. API Secret
   host:   Required. API Hostname
   debug:  0|1, If true, emit debugging telemetry
   user:   Optional username
   pass:   Optional password

Returns the HTTP response code and a perl hash reference containing
the response data.

'''

#Function definition to get auth token
def Auth_Request( p ):
  path = "/perl/api/v2/auth"
  method = 'POST'
  url  = "https://" + p['host'] + path
  date = int(time.time())
  
  if ( 'user' in p.keys() ):
    json_data = {
      'token'       : p['token'],
      'date'        : date,
      'user'        : p['user'],
      'pass'        : p['pass'],
      'signature'   : hmac.new(
                                  p['secret'].encode(),
                                  (p['token'] + "\n" + str(date) + "\n" + p['user'] + "\n" + p['pass'] + "\n").encode(),
                                  hashlib.sha256
                              ).hexdigest()
    }
  else:
    json_data = {
      'token'       : p['token'],
      'date'        : date,
      'signature'   : hmac.new(
                                  p['secret'].encode(),
                                  (p['token'] + "\n" + str(date) + "\n").encode(),
                                  hashlib.sha256
                              ).hexdigest()
    }

  header_arr = {'content-type': 'application/json'}
  try:
    params = json.dumps(json_data)
  except Exception as e:
    return { 'code' : '400', 'info' : { 'success' : 0, 'error' : "Failure encoding JSON request: " + str(e) } }

  return callAPI( url, params, header_arr, method, p['debug'] )


'''item ($code, $result) = Auth_Revoke($p);

$p:
   auth:   Required. API Authentication Code
   secret: Required. API Secret
   host:   Required. API Hostname
   debug:  0|1, If true, emit debugging telemetry

Returns the HTTP response code and a perl hash reference containing
the response data.

'''

#Function definition to revoke auth token
def Auth_Revoke( p ):
	p['path']   = "/perl/api/v2/auth"
	p['method'] = "DELETE"

	return API_Request( p )


#Function definition to make api request
def callAPI( url, params, header_arr, method, debug ):
  header_arr['User-Agent'] = "LuxSci APIv2 Python Client"
  if method == "GET":
    req = requests.get(url, data=params, headers=header_arr,  timeout=30)
  elif method == "PUT":
    req = requests.put(url, data=params, headers=header_arr,  timeout=30)
  else:
    req = requests.post(url, data=params, headers=header_arr,  timeout=30)
  
  json.loads(req.text)
  code = req.status_code

  try:
    data = json.loads(req.text)
  except Exception as e:
    if (debug):
      print ("JSON Parse Exception: " + str(e) + "\n")
    return { 'success' : 0, 'error' : "Non-JSON or unparsable data returned." }

  return { 'code' : code, 'data' : data }

################################################################################################

'''item (code, result) = API_Request(p);

p:
   auth:   Required. API Authentication Code
   secret: Required. API Secret
   host:   Required. API Hostname
   debug:  0|1, If true, emit debugging telemetry
   method: HTTP Method to use.  E.g. GET, PUT, POST, ...
   path:   path of the request. E.g. "/perl/api/v2/user/username/settings/timezones"
   data:   Hash reference of data to send.

Data will be turned into a JSON for PUT/POST calls, and a query string
for all others.

Returns the HTTP response code and a perl hash reference containing
the response data.

'''

#Function definition to create api request
def API_Request( p ):
  auth   = p['auth'];
  method = p['method'] if 'method' in p.keys() else "GET"
  path   = p['path'] if 'path' in p.keys() else "/perl/api/v2"
  qs     = ""
  hmac_key = ""
  json_data = None

  if (method == 'PUT' or method == 'POST'):
    try:
      json_data = json.dumps(p['data'])
      # Must be sure to be trimmed before applying hmac.
      json_data.strip(" ")
      hmac_key = hashlib.sha256(json_data.encode()).hexdigest()
    except Exception as e:
      if (p['debug']):
        print ("JSON Parse Exception: " + str(e) + "\n")
      return { 'code' : 400, 'info' : { 'success' : 0, 'error' : "Failure encoding JSON request: " + str(e) } }
  else:
    list_ar = list();
    if 'data' in p.keys():
      for key, value in p['data'].items():
         list_ar.append(quote(key, safe='') + "=" + quote(p['data'][key], safe=''))
    qs = str.join('&', list_ar)

  url = "https://" + p['host'] + p['path'] + "" if qs =="" else "?" + qs

  # Send the POST/PUT body
  if 'json_data' in locals():
    header_arr = {'content-type': 'application/json'}

  # Request signature
  to_sign = auth + "\n" + method.upper() + "\n" + path + "\n" + qs   + "\n" + hmac_key + "\n"

  sig = hmac.new( p['secret'].encode(),
                  to_sign.encode(),
                  hashlib.sha256
                ).hexdigest()

  if 'header_arr' in locals():
    header_arr["Cookie"] = "signature=" + auth + ":" + sig
  else:
    header_arr = {}
    header_arr["Cookie"] = "signature=" + auth + ":" + sig

  return callAPI( url, json_data, header_arr, method, p['debug'] )




print ("Authenticating:\n\n")

#call auth function to get auth token
p['token'] = token
res = Auth_Request( p )
t = res['data']['auth']

print ("Response code:- " + str(res['code']))
pprint(res['data'])


#Call API request function to get profile details
tmp_p = { 'auth'   : t,
          'method' : "GET",
          'path'   : "/perl/api/v2/user/" + p['user'] + "/profile" }
res = API_Request( dict(list(p.items()) + list(tmp_p.items())) )

print ("Response code:- " + str(res['code']))
pprint(res['data'])


#Call API request function to set/change profile name
tmp_p = { 'auth'   : t,
          'method' : "PUT",
          'path'   : "/perl/api/v2/user/" + p['user'] + "/profile",
          'data'   : { 'contact' : new_username }
        }
res = API_Request( dict(list(p.items()) + list(tmp_p.items())) )

print ("Response code:- " + str(res['code']))
pprint(res['data'])

#Call API request function to change user password
tmp_p = { 'auth'   : t,
          'method' : "PUT",
          'path'   : "/perl/api/v2/user/" + p['user'] + "/password",
          'data'   : { 'password' : new_password }
        }
res = API_Request( dict(list(p.items()) + list(tmp_p.items())) )

print ("Response code:- " + str(res['code']))
pprint(res['data'])