from urllib2_aws4auth import aws_urlopen, Request
from urllib2 import  HTTPError
from urllib import urlencode
import json
import system
import boto3
from pprint import pformat
	
STAGE = 'prod'
STAGE_CONFIG = {
	'alpha':{
		'region':'us-east-1',
		'endpoint': 'https://0wuzuy9rx3.execute-api.us-east-1.amazonaws.com/prod/user-activity-logger'
	},
	'beta': {
		'region':'us-east-1',
		'endpoint': 'https://33ymuc1b2a.execute-api.us-east-1.amazonaws.com/prod/user-activity-logger'
	},
	'prod': {
		'region':'us-east-1',
		'endpoint': 'https://ahikprejp4.execute-api.us-east-1.amazonaws.com/prod/user-activity-logger'
	}
}
REGION = STAGE_CONFIG.get(STAGE, 'alpha').get('region', 'us-east-1')
SERVICE = 'execute-api'
ENDPOINT = STAGE_CONFIG.get(STAGE, 'alpha').get('endpoint', 'https://0wuzuy9rx3.execute-api.us-east-1.amazonaws.com/prod/user-activity-logger')
LOGGER = system.util.getLogger('productMetrics')

def openSession():
	CREDS = boto3.Session().get_credentials()
	AWS_ACCESS_KEY_ID = CREDS.access_key
	AWS_SECRET_ACCESS_KEY = CREDS.secret_key
	TOKEN = CREDS.token
	
	OPENER = aws_urlopen(
		AWS_ACCESS_KEY_ID,
		AWS_SECRET_ACCESS_KEY,
		REGION,
		SERVICE,
		session_token=TOKEN,
		verify=False)
	return OPENER
	
def formatPayload(payload):
	"""Formats the payload based on what API expects to receive in the payload
		Also adds in some defaults (nulls) for the optional fields in case they are skipped from the payload
		Since defaults are not defined to required fields, will throw an error if they are not provided in the payload
	Args:
		payload (dict):all the fields that need to be sent to the API

	Returns:
		dict: dict formatted correctly for the API call
	"""
	data = {
			"project_id": "scada-activity-logger", #key used to log hashed user product metrics in backend, not the name of ignition project.
			"stage": payload.get("stage"),
			"plugin": "scada_activity_logger",
			"payload": {
			  "username": payload.get("username"),
			  "session_id": payload.get("session_id"),
			  "site": payload.get("site"),
			  "start_time": payload.get("start_time"),
			  "end_time": payload.get("end_time", None),
			  "user_UTCoffset": payload.get("user_UTCoffset", None),
			  "resource_type": payload.get("resource_type"),
			  "resource": payload.get("resource"),
			  "current_page": payload.get("current_page"),
			  "concurrent_users": payload.get("concurrent_users", getConcurrentUsers())
				}
			  }
	return data

def getConcurrentUsers():
	"""Get the number of concurrent user session for the current project

	Returns:
		int: number of concurrent users
	"""
	project_name = system.project.getProjectName()
	concurrent_users = len(system.perspective.getSessionInfo())
	return concurrent_users

def createActivityPayload(viewObj, resource_type, resource = None, current_page= None):
	"""Creates the activity payload for hashed user product metrics
		Typically called from view shutdown event script
		Uses the info from the view's custom param named activity_logger and session params to build the payload

	Args:
		viewObj: reference to the view (since custom param activity_logger is created on the view). If calling this function from a component pass self.view, if calling from view event scripts, pass self
		resource_type (string): page/session/click
		resource (string, optional): The resource that user interacted with. page name if interaction was with a page, feature/button name if it was a user click type interaction. Defaults to None.
		current_page (string, optional): Page name that the user is on when the interaction takes place. Defaults to None.

	Returns:
		dict: payload that needs to be formatted before sending to the API
	"""
	if viewObj.session.custom.product_metrics.enable and viewObj.session.props.device.type != 'designer':
		# since viewObj is a reference to the view, viewObj.session is reference to session
		session = viewObj.session
		stage = session.props.gateway.address
		user = session.props.auth.user.userName
		session_id = session.props.id
		site = session.custom.fc
		start_time = system.date.format(viewObj.custom.activityLogger.start_time, 'yyyy-MM-dd HH:mm:ss')
		end_time = None
		user_UTCoffset = session.props.device.timezone.utcOffset
		concurrent_users = getConcurrentUsers()
		if resource_type == 'page':
			end_time = system.date.format(system.date.now(), 'yyyy-MM-dd HH:mm:ss')
			try:
				pageid = viewObj.custom.activityLogger.pageid
				resource = pageid if resource == None else resource
				current_page = pageid if current_page == None else current_page
			except:
				pass
		if resource_type == 'click':
			start_time = system.date.format(system.date.now(), 'yyyy-MM-dd HH:mm:ss')
			end_time = None
			try:
				pageid = viewObj.custom.activityLogger.pageid
	#            resource = pageid if resource == None else resource
				current_page = pageid if current_page == None else current_page
			except:
				pass
				
		payload = {
					"stage": stage,
					"username": user,
					"session_id": session_id,
					"site": site,
					"start_time": start_time,
					"end_time": end_time,
					"resource_type": resource_type,
					"resource": resource,
					"current_page": current_page,
					"user_UTCoffset": user_UTCoffset,
					"concurrent_users": concurrent_users
					}
		activityPayload = formatPayload(payload)
		return activityPayload
	else:
		return None

def callActivityLoggerAPI(activityPayload):
	"""Makes a post api call with the provided payload to log hashed user product metrics
		Handles converting the payload from dict to json
		
	Args:
		activityPayload (dict): Final payload that needs to be sent to the API
								Function will convert the payload to json
	"""
	if activityPayload:
		opener = openSession()
		params = activityPayload
		payload = json.dumps(params)
		method = 'POST'
		# in the headers the Ignition session username (session.props.auth.user.userName) must be supplied as 'X-Ignition-User'
		headers = {
			'Content-type': 'application/json',
		}
		req = Request(url=ENDPOINT, method=method, data=payload, headers=headers)
		# open the request and process the read
		try:
			resp = opener(req)
			response = json.loads(resp.read())
			error = None
		except HTTPError, e:
			error = str(e)
			response = None
			system.perspective.print(error)
			LOGGER.info(error)
		return {'error': error, 'response':response }

def callLogger(viewObj, resource_type, resource = None, current_page= None):
	"""Combines the createActivityPayload and callActivityLoggerAPI to log hashed user product metrics
		Typically called from view shutdown event script
		Uses the info from the view's custom param named activity_logger and session params to build the payload
	"""
	activityPayload = createActivityPayload(viewObj, resource_type, resource, current_page)
	if activityPayload:
		callActivityLoggerAPI(activityPayload)
	


def testapi():
	print STAGE
	user = 'ankikarw'
	opener = openSession()
	params = {
		"project_id": "scada-activity-logger",
		"stage": "api test alpha",
		"plugin": "scada_activity_logger",
		"payload": {
		  "username": "user",
		  "session_id": "1234567989",
		  "site": "EWR4",
		  "start_time": "2023-11-06 10:45:25",
		  "end_time": "2023-11-06 10:57:18",
		  "user_UTCoffset": "-8",
		  "resource_type": "page",
		  "resource": "home",
		  "current_page": "home",
		  "concurrent_users": "5"
		}
	  }
	payload = json.dumps(params)
	method = 'POST'
	headers = {
		'Content-type': 'application/json',
	}
	req = Request(url=ENDPOINT, method=method, data=payload, headers=headers)
	# open the request and process the read
	try:
		resp = opener(req)
		response = json.loads(resp.read())
		error = None
		print response
	except HTTPError, e:
		error = str(e)
		response = None
		print error
		LOGGER.info(error)
	return {'error': error, 'response':response }