from celery import shared_task
# from demoapp.models import Widget
from Customer.models import *
from Driver.models import *
from AdminApp.models import *
from AdminApp.adminfunctions import assigndriverforparcel
import datetime

@shared_task
def assigndriverforparceltask():
	print('celery - assigndriverforparceltask started')
	from math import radians, cos, sin, asin, sqrt
	def haversine(lat1, lon1, lat2, lon2):
		lat1, lon1, lat2, lon2 = map(float, [lat1, lon1, lat2, lon2])# haversine formula 
		lat1, lon1, lat2, lon2 = map(radians, [lat1, lon1, lat2, lon2])# haversine formula 
		dlon = lon2 - lon1 
		dlat = lat2 - lat1 
		a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
		c = 2 * asin(sqrt(a)) 
		r = 6371 # Radius of earth in kilometers. Use 3956 for miles
		return (c * r)

	def get_nearestdriversdata_from_driversobj(senderlatitude, senderlongitude, driver_obj):
		nearestdrivers_data = []
		for driver in driver_obj:
			drivercoordinates_obj = DriverCoordinates.objects.filter(driver = driver).first()
			if drivercoordinates_obj:
				distance = haversine(senderlatitude, senderlongitude, drivercoordinates_obj.latitude, drivercoordinates_obj.longitude)
				# print(distance)
				nearestdrivers_data.append({
					'driverid' : driver.id,
					'drivervehicle' : driver.vehicletype.name,
					'distance' : distance,
					})
			else:
				pass
				# print('driver coordinates do not exist')
		if len(nearestdrivers_data) > 0:
			success = True
		else:
			success = False
		return (success, nearestdrivers_data)

	def sort_nearestdrivers_data(nearestdrivers_data):
		nearestdrivers_data = sorted(nearestdrivers_data, key = lambda i: i['distance'],reverse=False)
		# print(nearestdrivers_data)
		return(nearestdrivers_data)

	def get_nearestdriversdata_biggervehicles(senderlatitude, senderlongitude, vehicletypeid):
		# print('in get_nearestdriversdata_biggervehicles')
		nearestdrivers_data = []
		requiredvehicletype_obj = VehicleType.objects.filter(id = job.vehicletype.id).first()
		if requiredvehicletype_obj:
			vehiclecarryinglimit = requiredvehicletype_obj.carryinglimitinkg
			biggervehicletype_obj = VehicleType.objects.filter(carryinglimitinkg__gte = vehiclecarryinglimit).order_by('carryinglimitinkg')
			if biggervehicletype_obj:
				for biggervehicle in biggervehicletype_obj:
					driver_obj = DriverModel.objects.filter(status = 0, vehicletype = biggervehicle)
					if driver_obj:
						for driver in driver_obj:
							drivercoordinates_obj = DriverCoordinates.objects.filter(driver = driver).first()
							if drivercoordinates_obj:
								distance = haversine(senderlatitude, senderlongitude, drivercoordinates_obj.latitude, drivercoordinates_obj.longitude)
								# print(distance)
								nearestdrivers_data.append({
									'driverid' : driver.id,
									'drivervehicle' : driver.vehicletype.name,
									'distance' : distance,
									})
								success = True
							else:
								pass
								# print('driver coordinates do not exist')
		if len(nearestdrivers_data) > 0:
			success = True
		else:
			success = False
		return (success, nearestdrivers_data)
		
	backendcontrol_obj = BackendControl.objects.first()
	if backendcontrol_obj:
		if backendcontrol_obj.enable:
			# pendingcustomerjobs = CustomerJob.objects.filter(status = 0)
			# pendingcustomerjobs = CustomerJob.objects.filter(status = 0, id__gte = 296) # for test purpose
			
			pendingcustomerjobs = CustomerJob.objects.filter(status = 0, creation_date = datetime.date.today()) # for test purpose
			print(pendingcustomerjobs)
			# print('returning 11')
			# return ('11')
			for job in pendingcustomerjobs:
				nearestdrivers_data = []
				print(job)
				if job.senderlatitude and job.senderlongitude:
					# print('in first if')
					if job.vehicletype:
						print('\n')
						# print(str(job.id) + '  --  ' + job.senderlatitude + ',' + job.senderlongitude + '  --  ' + job.vehicletype.name)
						driver_obj = DriverModel.objects.filter(status = 0, vehicletype_id = job.vehicletype.id)
						# print(driver_obj)
						if len(driver_obj) == 0:
							# print('in if')
							success, nearestdrivers_data = get_nearestdriversdata_biggervehicles(senderlatitude = job.senderlatitude, senderlongitude = job.senderlongitude, vehicletypeid = job.vehicletype.id)
							if success:
								nearestdrivers_data = sort_nearestdrivers_data(nearestdrivers_data = nearestdrivers_data)
							else:
								pass
						else:
							# print('in else')
							success, nearestdrivers_data = get_nearestdriversdata_from_driversobj(senderlatitude = job.senderlatitude, senderlongitude = job.senderlongitude, driver_obj = driver_obj)
							if success:
								nearestdrivers_data = sort_nearestdrivers_data(nearestdrivers_data = nearestdrivers_data)
							else:
								success, nearestdrivers_data = get_nearestdriversdata_biggervehicles(senderlatitude = job.senderlatitude, senderlongitude = job.senderlongitude, vehicletypeid = job.vehicletype.id)
								if success:
									nearestdrivers_data = sort_nearestdrivers_data(nearestdrivers_data = nearestdrivers_data)
								else:
									pass
						# print(nearestdrivers_data)
						




						# print(nearestdrivers_data)
						if len(nearestdrivers_data) > 0:
							print('job assigned to driver with id: ' + str(nearestdrivers_data[0]['driverid']))	
							res = assigndriverforparcel(job.id,nearestdrivers_data[0]['driverid'])
							print(res)
							if res:
								job.status = 1
								job.save()		
						else:
							print('no driver found for job: ', job.id)
		else:
			print('Auto assign is disabled')
	print('end')
	print('celery - assigndriverforparceltask ended')
	return ('')


@shared_task
def repeat_order_cron():
	print('repeat_order_cron started')
	try:
		repeatorder_obj = RepeatOrder.objects.filter(is_cancelled = False)
		if repeatorder_obj:
			for repeatorder in repeatorder_obj:
				print('\n')
				print(repeatorder.id)
				start_date = datetime.datetime.strptime(repeatorder.start_date, "%d/%m/%Y")
				end_date = datetime.datetime.strptime(repeatorder.end_date, "%d/%m/%Y") 
				if start_date < end_date:
					if repeatorder.last_booking_date:
						last_booking_date = datetime.datetime.strptime(repeatorder.last_booking_date, "%d/%m/%Y")
						new_booking_date = last_booking_date + datetime.timedelta(days = int(repeatorder.repeat_after_days))
					else:
						new_booking_date = start_date + datetime.timedelta(days = int(repeatorder.repeat_after_days))
					if new_booking_date <= end_date:
						print(start_date)
						print(end_date)
						print(new_booking_date)
						customerjob_obj = CustomerJob.objects.filter(id = repeatorder.base_customerjob_id).first()
						if customerjob_obj:
							pass
							# print(customerjob_obj.order)
							# print(customerjob_obj.order.id)
							specialbooking_charges = 0.0
							if customerjob_obj.specialbooking:
								backendcontrol_obj = BackendControl.objects.filter(name = 'Special Booking Charges').first()
								if backendcontrol_obj:
									specialbooking_charges = backendcontrol_obj.price
								
							parceldelivery_charges = customerjob_obj.price
							totalamount = parceldelivery_charges + specialbooking_charges
							order_obj = Order.objects.create(customer = customerjob_obj.order.customer,ordertype = 1,  parceldelivery_charges = parceldelivery_charges, specialbooking_charges = specialbooking_charges, totalamount = totalamount)
							if order_obj:
								print('\norder_obj is successfully created\n')
								new_customerjob_obj = CustomerJob.objects.create(order = order_obj, customer = order_obj.customer, sendername = customerjob_obj.sendername, senderemail = customerjob_obj.senderemail, sendercountrycode = customerjob_obj.sendercountrycode, senderphone = customerjob_obj.senderphone, pickupaddress = customerjob_obj.pickupaddress, sendercity = customerjob_obj.sendercity, senderlatitude = customerjob_obj.senderlatitude, senderlongitude = customerjob_obj.senderlongitude, pickupspecialnote = customerjob_obj.pickupspecialnote, noofparcels = customerjob_obj.noofparcels, recipientname = customerjob_obj.recipientname, recipientcountrycode = customerjob_obj.recipientcountrycode, recipientphone = customerjob_obj.recipientphone, recipientlatitude = customerjob_obj.recipientlatitude, recipientlongitude = customerjob_obj.recipientlongitude, dropoffaddress = customerjob_obj.dropoffaddress, dropoffspecialnote = customerjob_obj.dropoffspecialnote, length = customerjob_obj.length, width = customerjob_obj.width, height = customerjob_obj.height, weight = customerjob_obj.weight, parceltype = customerjob_obj.parceltype, pickuptimeslot = customerjob_obj.pickuptimeslot, dropofftimeslot = customerjob_obj.dropofftimeslot, vehicletype = customerjob_obj.vehicletype, image = customerjob_obj.image.name, specialbooking = customerjob_obj.specialbooking, specialbooking_charge = specialbooking_charge, creation_date = new_booking_date.date())
								if new_customerjob_obj:
									if repeatorder.pickuptimeslot and repeatorder.dropofftimeslot:
										new_customerjob_obj.pickuptimeslot = repeatorder.pickuptimeslot
										new_customerjob_obj.dropofftimeslot = repeatorder.dropofftimeslot
										new_customerjob_obj.save()
									print('\nnew_customerjob_obj is created\n')
									try:
										print('before generateqrcode function call')
										generateqrcode(id_val = new_customerjob_obj.id)
										print('after function call')
									except Exception as e:
										print(e)
									try:
										res = generateparcelpdf(new_customerjob_obj.id)
										print(res)
									except Exception as e:
										print(e)
								else:
									print('\nnew_customerjob_obj is not created\n')	
								repeatorder.last_booking_date = new_booking_date.strftime("%d/%m/%Y")
								repeatorder.save()
							else:
								pass
								print('\norder_obj is not created\n')
							
	except Exception as e:
		print(e)