from edge_engine.common.logsetup import logger
from pymongo import MongoClient
from scripts.common.config import MONGO_DB_OBJ, APP_MONGO_COLLECTION


class AlarmUtils:
	def __init__(self):
		self.attendance_alarm_configuration_collection = MONGO_DB_OBJ[
			APP_MONGO_COLLECTION.get('alarmConfigurationCollection')]
		self.attendance_tag_collection = MONGO_DB_OBJ[APP_MONGO_COLLECTION.get('tagConfiguration')]
		self.attendance_alarm_priority_collection = MONGO_DB_OBJ[APP_MONGO_COLLECTION.get('alarmPriorityCollection')]

	def get_alarms(self):
		alarms = [each for each in self.attendance_alarm_configuration_collection.find({}, {'_id': 0})]
		return alarms

	def get_priority_name(self, priority):
		data = self.attendance_alarm_priority_collection.find_one({'id': priority}, {'_id': 0})
		priority_name = data.get('priority_name')
		return priority_name

	def build_condition_string(self, rule):
		condition = rule['condition']
		tag_name = self.attendance_tag_collection.find_one({'tag_id': rule['leftHandSide']['tag']}, {'Tag Name': 1})[
			'Tag Name']
		condition_value = rule['rightHandSide']['customValue']
		condition_name = f"{tag_name} {condition} {condition_value}"
		return condition_name, tag_name

	def build_message(self, each_alarm, tag_value):
		alarmTemplate = each_alarm['alarmTemplate']
		alarmTemplate = alarmTemplate.replace('[Tag Name]',
											  self.build_condition_string(each_alarm['ruleSets'][0]['rules'][0])[1])
		alarmTemplate = alarmTemplate.replace('[Tag Value]', str(tag_value))
		return alarmTemplate

	def process_data(self, tag_value, av_alarms):
		# add mongo query to fetch alarms
		if av_alarms:
			event_decision = {
				"Safe": False,
				"Risky": False,
				"Message": self.build_message(av_alarms[0], tag_value)
			}
			for each_alarm in av_alarms:
				try:
					event_decision = self.process_alarm(alarm_record=each_alarm, tag_value=tag_value,
														event_decision=event_decision)
				except Exception as e:
					raise Exception(str(e))
		else:
			event_decision = {
				"Safe": False,
				"Risky": False,
				"Message": ""
			}
			logger.debug(" no alarms found")
		return event_decision

	def process_alarm(self, alarm_record, tag_value, event_decision):
		try:
			try:

				rule_set_operation = "and" if alarm_record["ruleSetAndOrOperationData"][
					"isAnd"] else "or"
				rule_set_outputs = []
				for each_rule_set in alarm_record["ruleSets"]:
					try:
						rule_operation = "and" if each_rule_set["ruleAndOrOperationData"][
							"isAnd"] else "or"
						rule_output = []
						for each_rule in each_rule_set["rules"]:
							try:
								primary_output = self.alarm_rule_parser(each_rule, tag_value)

								if primary_output is not None:
									rule_output.append(primary_output)
							except Exception as e:
								logger.exception("Exception in parsing rule:" + str(e))

						temp_output = self.aggregate_result(rule_operation, rule_output)
						if temp_output is not None:
							rule_set_outputs.append(temp_output)
					except Exception as e:
						logger.exception("Exception during parsing of individual rule set:" + str(e))
				final_output = self.aggregate_result(rule_set_operation, rule_set_outputs)
				# print("alarm condition output:", final_output)
				logger.debug(
					"{} {} {} {}".format(self.build_condition_string(alarm_record['ruleSets'][0]['rules'][0])[0],
										 tag_value,
										 self.get_priority_name(alarm_record['priority']),
										 final_output))
				if self.get_priority_name(alarm_record['priority']) == 'Safe' and final_output == True:
					event_decision['Safe'] = True
				elif self.get_priority_name(alarm_record['priority']) == 'Risky' and final_output == True:
					event_decision['Risky'] = True
				# if final output is True, condition satisfied, if not condition not satisfied
				return event_decision
			except Exception as e:
				logger.exception("Exception during alarm rule parsing:" + str(e))

		except Exception as e:
			logger.exception("Exception during alarm rule parsing:" + str(e))
		# logger.debug("EXIT: Alarm Parser")

	def get_tag_value(self, tag_value):
		try:
			return tag_value
		except Exception as e:
			logger.exception(" Unable to fetch tag value:" + str(e))

	def alarm_rule_parser(self, rule, tag_value):
		try:
			left_side_value = self.get_tag_value(tag_value)
			right_opr = str(rule["rightHandSide"][rule["rightHandSide"]["compareOption"]])

			final_opr = ""
			final_opr += str(left_side_value) + " "
			final_opr += rule["condition"] + " "
			final_opr += str(right_opr) + " "
			rule_result = eval(final_opr)
			return rule_result
		except Exception as e:
			logger.exception("Exception in parsing rule in alarms:" + str(e))
			return None

	def aggregate_result(self, condition, output):
		try:
			final_response = ""
			if len(output) == 0:
				logger.debug("empty array found inside aggregate result")
				return None
			# logger.debug("OUTPUT:" + str(output))
			for i in range(0, len(output)):
				final_response += str(output[i]) + " "
				if i <= len(output) - 2:
					final_response += condition + " "
			final_response = eval(final_response)
			# logger.debug("Result: " + str(final_response))
			return final_response
		except Exception as e:
			logger.exception("Exception in parsing:" + str(e))
			return None
