from flask import Flask, jsonify, render_template, url_for, request, redirect, json
from datetime import datetime, timedelta, date

import uuid

# File imports
from routes import app, bookings_logger
from routes import db
from database.bookings_notes import Note
from variables import *

from functions.date_operators import *
from functions.currency_operators import *
from functions.booking_snippets import *
from functions.validation import *
from functions.async_functions import AsyncRequests


def close(self):
	self.session.close()


### Email Functions ###
def RangerNoteMailer(email_data):
	recipient = email_data["recipient"]
	sender = email_data["sender"]

	booking_details = {}
	booking_details["booking_ref_code"] = email_data["booking_ref"]
	booking_details["today"] = email_data["today"]
	booking_details["copyright_year"] = datetime.now().strftime("%Y")
	booking_details["name"] = email_data["name"]
	booking_details["note"] = email_data["note"]

	sg = sendgrid.SendGridAPIClient(apikey=app.config["SENDGRID_API_KEY"])

	from_email = Email(sender)
	to_email = Email(recipient)
	subject = email_data["subject"]
	content = Content(
		"text/html",
		render_template("checkpoint_alert.html", data=booking_details))
	mail = Mail(from_email, subject, to_email, content)

	try:
		response = sg.client.mail.send.post(request_body=mail.get())
		return jsonify({'message': str(response)})
	except Exception as e:
		trace = traceback.format_exc()
		raise Exception("Error: " + str(e) + ". Trace: " + trace)


def RangerUnticketedNoteMailer(email_data):
	recipient = email_data["recipient"]
	sender = email_data["sender"]

	alert_details = {}
	alert_details["destination"] = email_data["destination"]
	alert_details["today"] = email_data["today"]
	alert_details["copyright_year"] = datetime.now().strftime("%Y")
	alert_details["name"] = email_data["name"]
	alert_details["adult"] = email_data["adult"]
	alert_details["children"] = email_data["children"]
	alert_details["vehicle_reg"] = email_data["vehicle_reg"]
	alert_details["unticketed_alert"] = email_data["unticketed_alert"]

	sg = sendgrid.SendGridAPIClient(apikey=app.config["SENDGRID_API_KEY"])

	from_email = Email(sender)
	to_email = Email(recipient)
	subject = email_data["subject"]
	content = Content(
		"text/html",
		render_template("checkpoint_unticketed_alert.html",
						data=alert_details))
	mail = Mail(from_email, subject, to_email, content)

	try:
		response = sg.client.mail.send.post(request_body=mail.get())
		return jsonify({'message': str(response)})
	except Exception as e:
		trace = traceback.format_exc()
		raise Exception("Error: " + str(e) + ". Trace: " + trace)


def updateRangerNoteMailer(email_data):
	recipient = email_data["recipient"]
	sender = email_data["sender"]

	booking_details = {}
	booking_details["booking_ref_code"] = email_data["booking_ref"]
	booking_details["today"] = email_data["today"]
	booking_details["copyright_year"] = datetime.now().strftime("%Y")
	booking_details["name"] = email_data["name"]
	booking_details["note"] = email_data["note"]
	booking_details["update_note"] = email_data["update_note"]

	sg = sendgrid.SendGridAPIClient(apikey=app.config["SENDGRID_API_KEY"])

	from_email = Email(sender)
	to_email = Email(recipient)
	subject = email_data["subject"]
	content = Content(
		"text/html",
		render_template("checkpointupdate_alert.html", data=booking_details))
	mail = Mail(from_email, subject, to_email, content)

	try:
		response = sg.client.mail.send.post(request_body=mail.get())

		return jsonify({'message': str(response)})
	except Exception as e:
		trace = traceback.format_exc()
		raise Exception("Error: " + str(e) + ". Trace: " + trace)


def updateUnticketedRangerNoteMailer(email_data):
	recipient = email_data["recipient"]
	sender = email_data["sender"]

	booking_details = {}
	booking_details["booking_ref_code"] = email_data["booking_ref"]
	booking_details["today"] = email_data["today"]
	booking_details["copyright_year"] = datetime.now().strftime("%Y")
	booking_details["name"] = email_data["name"]
	booking_details["note"] = email_data["note"]
	booking_details["update_note"] = email_data["update_note"]
	booking_details["unticketed_alert"] = email_data["unticketed_alert"]

	sg = sendgrid.SendGridAPIClient(apikey=app.config["SENDGRID_API_KEY"])

	from_email = Email(sender)
	to_email = Email(recipient)
	subject = email_data["subject"]
	content = Content(
		"text/html",
		render_template("checkpointupdate_unticketed_alert.html",
						data=booking_details))
	mail = Mail(from_email, subject, to_email, content)

	try:
		response = sg.client.mail.send.post(request_body=mail.get())

		return jsonify({'message': str(response)})
	except Exception as e:
		trace = traceback.format_exc()
		raise Exception("Error: " + str(e) + ". Trace: " + trace)


@app.route("/note/new", methods=["POST"])
def addNewNote():
	validation_list = [{
		"field": "booking_id",
		"alias": "Booking ID"
	}, {
		"field": "note"
	}, {
		"field": "session_id",
		"alias": "Session ID"
	}]

	messages = fieldValidation(request.json, validation_list)

	if messages:
		return jsonify({"messages": messages}), 422

	try:
		if request.json["show_on_invoice"]:
			show_on_invoice = bool(request.json["show_on_invoice"])
		else:
			show_on_invoice = None
	except Exception:
		show_on_invoice = None

	note = Note(booking_notes_public_id=str(uuid.uuid4()),
				booking_id=request.json["booking_id"],
				note=request.json["note"],
				show_on_invoice=show_on_invoice,
				session_id=request.json["session_id"],
				created_at=datetime.now())

	db.session.add(note)

	try:
		db.session.commit()
		close(db)

		message = []
		message.append("New note saved.")
		return jsonify({"message": message}), 201

	except Exception:
		db.session.rollback()
		close(db)

		message = []
		message.append(
			"There was an error saving the note. Try again later."), 422


@app.route("/inspection-note/new", methods=["POST"])
def addNewInsectionNote():
	validation_list = [{
		"field": "booking_id",
		"alias": "Booking ID"
	}, {
		"field": "note"
	}, {
		"field": "session_id",
		"alias": "Session ID"
	}]
	messages = fieldValidation(request.json, validation_list)
	if messages:
		return jsonify({"messages": messages}), 422

	try:

		show_on_invoice = None
		ranger_note = 1
		if request.json["alert"]:
			alert = request.json["alert"]
		else:
			alert = None
	except Exception:
		show_on_invoice = None
		ranger_note = 1
		alert = None

	message = []

	note = Note(booking_notes_public_id=str(uuid.uuid4()),
				booking_id=request.json["booking_id"],
				note=request.json["note"],
				show_on_invoice=show_on_invoice,
				session_id=request.json["session_id"],
				ranger_note=ranger_note,
				alert=alert,
				created_at=datetime.now())

	db.session.add(note)

	booking_activity = BookingActivity(
		booking_activity_public_id=str(uuid.uuid4()),
		booking_id=request.json["booking_id"],
		booking_activity_description="An inspection note was created",
		session_id=request.json["session_id"],
		created_at=datetime.now())
	db.session.add(booking_activity)
	try:
		db.session.commit()
		close(db)
	except Exception:
		db.session.rollback()
		close(db)
		message.append("An error occured while saving inspection Note.")
		return jsonify({"message": message}), 412

	message = []

	if alert == True:
		return_booking = db.session.query(Booking)\
		 .filter(Booking.booking_public_id == request.json["booking_id"])\
		 .first()

		if not return_booking:
			message.append("An error occured while sending an alert.")
			return jsonify({"message": message}), 412
		else:
			booking_ref = return_booking.booking_ref_code
		user_info = {}
		getBookingSessionUser(request.json["session_id"], user_info)
		email = user_info["email"]
		name = user_info["session_user"]
		facility_mailing_list = ["obtsalert@olpejetaconservancy.org"]

		try:
			if len(facility_mailing_list) > 0:
				for each_email in facility_mailing_list:
					email_data = {}
					email_data["recipient"] = each_email
					email_data["sender"] = email
					email_data[
						"subject"] = "Booking Alert (#" + booking_ref + ")"
					email_data["note"] = request.json["note"]
					email_data["name"] = name
					email_data["booking_id"] = request.json["booking_id"]

					email_data["today"] = datetime.now().strftime("%B %Y")
					email_data["booking_ref"] = booking_ref

					try:
						RangerNoteMailer(email_data)
						message.append("Alert sent successfully.")
						booking_activity = BookingActivity(
							booking_activity_public_id=str(uuid.uuid4()),
							booking_id=request.json["booking_id"],
							booking_activity_description="Alert email sent",
							session_id=request.json["session_id"],
							created_at=datetime.now())
						db.session.add(booking_activity)
						try:
							db.session.commit()
							close(db)
						except Exception:
							db.session.rollback()
							close(db)
						return jsonify({"message": message}), 201
					except Exception as e:
						raise Exception(str(e))
			else:
				pass
		except KeyError:
			pass

	else:
		message.append("Booking Note successfully saved.")
		return jsonify({"message": message}), 201


@app.route("/inspection-unticketed-note/new", methods=["POST"])
def addNewUnticketedInsectionNote():

	destination = request.json.get('unticketed_destination', '')
	adults = request.json.get('unticketed_adults')
	children = request.json.get('unticketed_children')
	vehicle_reg = request.json.get('unticketed_vehicle_registration')
	#gate = request.json.get('unticketed_gate', '')
	#infants = request.json.get('unticketed_infants', '')
	#guide = request.json.get('unticketed_guide', '')

	################new code###############################
	# convert_to_booking = request.json['convert_to_booking']
	# if convert_to_booking:
	# 	convert_to_booking = 1
	# else:
	# 	convert_to_booking = 0
    ###################################################
	session_id = request.json.get('session_id')
	messages = []
	# Checking if all fields have been provided
	if not destination.strip():
		messages.append("Destination has not been Provided!")
	if not session_id.strip():
		messages.append("Registerer has not been Provided!")
	if adults == 0 and children == 0:
		messages.append("Number of pax has not been Provided!")
	if not vehicle_reg:
		messages.append("Vehicle registration has not been Provided!")
	# if not gate.strip():
	# 	messages.append("gate has not been Provided!")

	if messages:
		return jsonify({"messages": messages}), 422
	return_vehicle_reg = db.session.query(Note)\
	  .add_columns(Note.booking_notes_public_id)\
	  .filter(Note.vehicle_reg.ilike(vehicle_reg))\
	  .all()

	 ###if return_vehicle_reg:
	 ###	messages.append(
	 ###		"Unticketed alert for the given vehicle has already been raised")
	 ###	return jsonify({"messages": messages}), 422

	note_detail = 'Unticketed guests'
	try:
		show_on_invoice = None
		ranger_note = 2
		if request.json["alert"]:
			alert = request.json["alert"]
		else:
			alert = None
	except Exception:
		show_on_invoice = None
		ranger_note = 1
		alert = None

	message = []
	booking_notes_id = str(uuid.uuid4())
	booking_notes_id_reference = booking_notes_id[:5]
	note = Note(booking_notes_public_id=booking_notes_id,
				note=note_detail,
				destination=destination,
				#gate=gate,
				vehicle_reg=vehicle_reg,
				adult=adults,
				children=children,
				show_on_invoice=show_on_invoice,
				session_id=request.json["session_id"],
				ranger_note=ranger_note,
				alert=alert,
				created_at=datetime.now())#,
				#guide=guide,
				#infants=infants)

	db.session.add(note)
################################new code##############################
	# if convert_to_booking == 1:
	
	# 	booking = Booking(booking_public_id=str(uuid.uuid4()),
	# 				  booking_type="GB601X10",#booking_type,
	# 				  booking_check_in_date=datetime.now(),
	# 				  booking_check_out_date=datetime.now(),
	# 				  booking_done_by= "TBA",#first_name + " " + last_name,
	# 				  booking_ref_code=str(uuid.uuid4())[:10],
	# 				  status="ecc9e63f-a2f1-4998-bc07-8de2eb7b8f65",
	# 				  currency="ecc9e63f-a2f1-4998-bc07-8de2eb7b8f64",
	# 				  currency_buying_rate_at_time=1,
	# 				  currency_selling_rate_at_time=1,
	# 				  session_id=session_id,
	# 				  created_at=datetime.now(),
	# 				  updated_at=datetime.now())

	# db.session.add(booking)
#######################################################################
	message = []

	if alert == True:
		print("and hrere")

		user_info = {}
		getBookingSessionUser(request.json["session_id"], user_info)
		email = user_info["email"]
		name = user_info["session_user"]
		destination_db= db.session.query(Destination)\
		 .filter(Destination.gatepass_destination_public_id == destination)\
		 .options(FromCache(db_cache))\
		 .first()
		destination_name = destination_db.gatepass_destination_name
		facility_mailing_list = ["obtsalert@olpejetaconservancy.org"]
		try:
			if len(facility_mailing_list) > 0:
				for each_email in facility_mailing_list:
					email_data = {}
					email_data["recipient"] = each_email
					email_data["sender"] = email
					email_data[
						"subject"] = "Unticketed Booking Alert (" + booking_notes_id_reference + ")"
					email_data["name"] = name
					email_data["destination"] = destination_name
					email_data["adult"] = int(adults)
					email_data["children"] = int(children)
					email_data["vehicle_reg"] = vehicle_reg
					email_data["unticketed_alert"] = booking_notes_id_reference
					email_data["today"] = datetime.now().strftime("%B %Y")

					try:
						RangerUnticketedNoteMailer(email_data)
						try:
							db.session.commit()
							close(db)
							message.append("Alert sent successfully.")
							return jsonify({"message": message}), 201
						except Exception as e:
							print(e)
							db.session.rollback()
							close(db)
							message.append(
								"An error occured while saving inspection Note."
							)
							return jsonify({"message": message}), 412

					except Exception as e:
						raise Exception(str(e))
			else:
				pass
		except KeyError:
			pass

	else:
		message.append("Note successfully saved.")
		return jsonify({"message": message}), 201


@app.route("/inspection-note/update", methods=["POST"])
def updateNewInsectionNote():
	validation_list = [{
		"field": "booking_public_id",
		"alias": "Booking ID"
	}, {
		"field": "note"
	}, {
		"field": "session_id",
		"alias": "Session ID"
	}]
	messages = fieldValidation(request.json, validation_list)
	if messages:
		return jsonify({"messages": messages}), 422

	try:

		show_on_invoice = None
		ranger_note = 1
		if request.json["alert"]:
			alert = request.json["alert"]
		else:
			alert = None
	except Exception:
		show_on_invoice = None
		ranger_note = 1
		alert = None

	message = []

	note = Note(booking_notes_public_id=str(uuid.uuid4()),
				booking_id=request.json["booking_public_id"],
				note=request.json["update_note"],
				update_note=request.json["note_public_id"],
				show_on_invoice=show_on_invoice,
				session_id=request.json["session_id"],
				ranger_note=ranger_note,
				alert=alert,
				created_at=datetime.now())

	db.session.add(note)

	booking_activity = BookingActivity(
		booking_activity_public_id=str(uuid.uuid4()),
		booking_id=request.json["booking_public_id"],
		booking_activity_description=
		"An inspection update note was created on booking note " +
		request.json["note_public_id"],
		session_id=request.json["session_id"],
		created_at=datetime.now())
	db.session.add(booking_activity)

	message = []

	return_booking = db.session.query(Booking)\
	 .filter(Booking.booking_public_id == request.json["booking_public_id"])\
	 .first()

	if not return_booking:
		message.append("An error occured while sending an update alert.")
		return jsonify({"message": message}), 412
	else:
		booking_ref = return_booking.booking_ref_code
	user_info = {}
	getBookingSessionUser(request.json["session_id"], user_info)
	email = user_info["email"]
	name = user_info["session_user"]
	facility_mailing_list = ["obtsalert@olpejetaconservancy.org"]

	try:
		if len(facility_mailing_list) > 0:
			for each_email in facility_mailing_list:
				email_data = {}
				email_data["recipient"] = each_email
				email_data["sender"] = email
				email_data[
					"subject"] = "Booking Alert Update(#" + booking_ref + ")"
				email_data["note"] = request.json["note"]
				email_data["update_note"] = request.json["update_note"]
				email_data["name"] = name
				email_data["booking_id"] = request.json["booking_public_id"]

				email_data["today"] = datetime.now().strftime("%B %Y")
				email_data["booking_ref"] = booking_ref

				try:
					updateRangerNoteMailer(email_data)
					message.append("Alert updated successfully.")
					booking_activity = BookingActivity(
						booking_activity_public_id=str(uuid.uuid4()),
						booking_id=request.json["booking_public_id"],
						booking_activity_description=
						"Alert update email sent for note" +
						request.json["note_public_id"],
						session_id=request.json["session_id"],
						created_at=datetime.now())
					db.session.add(booking_activity)
					try:
						db.session.commit()
						close(db)
					except Exception:
						db.session.rollback()
						close(db)
					return jsonify({"message": message}), 201
				except Exception as e:
					raise Exception(str(e))
		else:
			pass
	except Exception as e:
		raise Exception(str(e))


@app.route("/unticketed-inspection-note/update", methods=["POST"])
def updateUnticketedInsectionNote():
	validation_list = [{
		"field": "booking_ref",
		"alias": "Booking ref"
	}, {
		"field": "note"
	}, {
		"field": "session_id",
		"alias": "Session ID"
	}]
	messages = fieldValidation(request.json, validation_list)

	if messages:
		return jsonify({"messages": messages}), 422

	booking_reference = request.json["booking_ref"]
	note_public_id = request.json["note_public_id"]
	booking_notes_id_reference = note_public_id[:5]

	return_booking = db.session.query(Booking)\
	   .filter(Booking.booking_ref_code == booking_reference)\
	   .first()

	if not return_booking:
		message = []
		message.append("The booking reference " + booking_reference +
					   " is not in the system.")
		return jsonify({"message": message}), 412
	try:
		show_on_invoice = None
		ranger_note = 1
		if request.json["alert"]:
			alert = request.json["alert"]
		else:
			alert = None
	except Exception:
		show_on_invoice = None
		ranger_note = 1
		alert = None

	message = []

	note = Note(booking_notes_public_id=str(uuid.uuid4()),
				booking_id=return_booking.booking_public_id,
				note=request.json["update_note"],
				update_note=request.json["note_public_id"],
				show_on_invoice=show_on_invoice,
				session_id=request.json["session_id"],
				ranger_note=ranger_note,
				alert=alert,
				created_at=datetime.now())

	db.session.add(note)

	message = []
	user_info = {}
	getBookingSessionUser(request.json["session_id"], user_info)
	email = user_info["email"]
	name = user_info["session_user"]
	facility_mailing_list = ["obtsalert@olpejetaconservancy.org"]

	try:
		if len(facility_mailing_list) > 0:
			for each_email in facility_mailing_list:
				email_data = {}
				email_data["recipient"] = each_email
				email_data["sender"] = email
				email_data[
					"subject"] = "Unticketed Booking Alert Update(" + booking_notes_id_reference + ")"
				email_data["note"] = request.json["note"]
				email_data["update_note"] = request.json["update_note"]
				email_data["name"] = name
				email_data["booking_id"] = request.json["booking_public_id"]
				email_data["unticketed_alert"] = booking_notes_id_reference
				email_data["today"] = datetime.now().strftime("%B %Y")
				email_data["booking_ref"] = booking_reference

				try:
					updateUnticketedRangerNoteMailer(email_data)
					message.append("Alert updated successfully.")
					booking_activity = BookingActivity(
						booking_activity_public_id=str(uuid.uuid4()),
						booking_id=return_booking.booking_public_id,
						booking_activity_description=
						"An inspection update note was created and alert update email sent for note"
						+ request.json["note_public_id"],
						session_id=request.json["session_id"],
						created_at=datetime.now())
					db.session.add(booking_activity)
					try:
						db.session.commit()
						close(db)
					except Exception:
						db.session.rollback()
						close(db)
					return jsonify({"message": message}), 201
				except Exception as e:
					raise Exception(str(e))
		else:
			pass
	except Exception as e:
		raise Exception(str(e))


@app.route("/note/delete", methods=["PATCH"])
def deleteNote():
	validation_list = [{
		"field": "note_id",
		"alias": "Note ID"
	}, {
		"field": "session_id",
		"alias": "Session ID"
	}]

	messages = fieldValidation(request.json, validation_list)

	if messages:
		return jsonify({"messages": messages}), 422

	get_note = db.session.query(Note)\
	   .filter(Note.deletion_marker == None)\
	   .filter(Note.booking_notes_public_id == request.json["note_id"])\
	   .first()

	if not get_note:
		message = []
		message.append(
			"The note either does not exist or has already been deleted.")
		return jsonify({"message": message}), 412

	else:
		get_note.deletion_marker = 1
		get_note.session_id = request.json["session_id"]
		get_note.updated_at = datetime.now()

		try:
			db.session.commit()
			close(db)

			message = []
			message.append("Successfully deleted the note.")
			return jsonify({"message": message}), 200

		except Exception:
			db.session.rollback()
			close(db)

			message = []
			message.append(
				"There was an error deleting the note. Try again later.")
			return jsonify({"message": message}), 422


@app.route("/note/view/inpected-alerted-note/<note_id>")
# @bookings_logger.logWrapper()
def view_single_alert_note(note_id):

	get_ranger_note = db.session.query(Note)\
	  .add_columns(Note.session_id,Note.alert,Note.ranger_note,Note.booking_id,Note.note,Note.update_note,Note.booking_notes_public_id,Note.created_at)\
	  .filter(Note.deletion_marker == None)\
	  .filter(Note.booking_notes_public_id == note_id)\
	  .filter(Note.update_note == None)\
	  .options(FromCache(db_cache))\
	  .first()

	output = []
	if get_ranger_note:
		return_data = {}
		user_info = {}
		try:
			getBookingSessionUser(get_ranger_note.session_id, user_info)
			return_data["session_user"] = user_info["session_user"]
			return_data["session_id"] = user_info["session_id"]
		except Exception as e:
			return_data["session_user"] = ''
			return_data["session_id"] = ''

		return_data["note_public_id"] = get_ranger_note.booking_notes_public_id
		return_data["note"] = get_ranger_note.note
		return_data["alert"] = get_ranger_note.alert
		return_data["created_at"] = get_ranger_note.created_at
		return_data["booking_id"] = get_ranger_note.booking_id
		return_data["ranger_note"] = get_ranger_note.ranger_note

		get_ranger_note_updates = db.session.query(Note)\
		 .add_columns(Note.session_id,Note.alert,Note.booking_id,Note.note,Note.update_note,Note.booking_notes_public_id,Note.created_at)\
		 .filter(Note.deletion_marker == None)\
		 .filter(Note.ranger_note == 1)\
		 .filter(Note.update_note == get_ranger_note.booking_notes_public_id)\
		 .order_by(Note.created_at.desc())\
		 .options(FromCache(db_cache))\
		 .all()

		if len(get_ranger_note_updates) > 0:
			update_ranger_notes = []
			for update_note in get_ranger_note_updates:
				update_ranger_note_ob = {}
				update_ranger_note_ob["note"] = update_note.note
				update_ranger_note_ob["created_at"] = update_note.created_at
				update_ranger_note_ob["update_note"] = update_note.update_note
				user_info_update = {}
				try:
					getBookingSessionUser(update_note.session_id,
										  user_info_update)
					update_ranger_note_ob["session_user"] = user_info_update[
						"session_user"]
					update_ranger_note_ob["session_id"] = user_info_update[
						"session_id"]
				except Exception as e:
					update_ranger_note_ob["session_user"] = ''
					update_ranger_note_ob["session_id"] = ''
				try:
					return_booking = db.session.query(Booking)\
					.filter(Booking.booking_public_id == update_note.booking_id)\
					.first()

					booking_ref_code = return_booking.booking_ref_code
					booking_public_id = return_booking.booking_public_id

					update_ranger_note_ob["booking_ref_code"] = booking_ref_code
					update_ranger_note_ob[
						"booking_public_id"] = booking_public_id
				except Exception as e:
					update_ranger_note_ob["booking_ref_code"] = ''
					update_ranger_note_ob["booking_public_id"] = ''
				update_ranger_notes.append(update_ranger_note_ob)

			return_data["update_notes"] = update_ranger_notes
		else:
			return_data["update_notes"] = []

		output.append(return_data)
		print("return_data")
		print(return_data)

		return jsonify({"data": output}), 200

	else:
		message = []
		message.append(
			"The chosen note does not seem to appear in the system.")
		return jsonify({"message": message}), 412
