import pandas as pd
import numpy as np
from dataclasses import dataclass
from geoplotlib.utils import haversine
import matplotlib.path as mplPath
from os.path import exists
import random
import json

from de2.routing import get_graph, pathfinder, find_percentage_point_in_path as fpp

docks = pd.read_csv("berths.csv")
polygons = {k["lpl_id"]: eval(k["polygon"]) for _, k in docks.iterrows()}

tugs = pd.read_excel("20230405_Tugs.xlsx", dtype={"MMSI": str, "NAME": str})
tmap = {}
for _, row in tugs.iterrows():
	tmap[row["MMSI"]] = row["NAME"]

with open("paths/endpointsWGS84.json", 'r') as file:
	endpoints = json.load(file)["features"]

@dataclass
class Vessel:
	mmsi: str
	name: str
	start: int
	end: int
	location: str
	lonlat_s: tuple
	lonlat_t: tuple
	distance: float
	task: str

def is_inside(lon, lat, polygon):
	ppath = mplPath.Path(np.array(polygon))
	return ppath.contains_point((lon, lat))


def get_dock(lon, lat):
	# loop through all dock indexes and do insideness checks
	for pid, poly in polygons.items():
		if is_inside(lon, lat, poly):
			return pid
	return ""

def get_closest_endpoint(lon, lat):
	dist = float('inf')
	point = None
	for p in endpoints:
		D = haversine(lon, lat, p["geometry"]["x"], p["geometry"]["y"])
		if D < dist:
			dist = D
			point = p
	return point, dist


def analyze(fname):
	if not exists(fname):
		print(fname, "does not exist!")
		return None
	df = pd.read_csv(fname, dtype={"mmsi": str})
	df.sort_values(by=["ts"], inplace=True)

	# res = pd.DataFrame(columns=["mmsi", "name", "start", "end", "location", "source_lon", "source_lat",
	#                             "target_lon", "target_lat", "distance", "task"])
	res = pd.DataFrame(columns=["mmsi", "start", "ETA", "source", "target", "task"])

	# graph = get_graph()

	task = random.choice([0, 1])
	tasks = ["tugging", "sailing"]

	first = df.iloc[0]
	vessel = Vessel(first["mmsi"], tmap[str(first["mmsi"])], first["ts"], -1, (first["lon"], first["lat"]),
	                (first["lon"], first["lat"]), (first["lon"], first["lat"]), 0.0, tasks[task])

	# if exists("../results-de/%s-de.csv" % str(vessel.mmsi)):
	# 	print("Already done %s" % str(vessel.mmsi))
	# 	return None

	# in_dock = get_dock(first["lon"], first["lat"]) != ""
	# time = first["ts"]
	# new_loc = get_dock(first["lon"], first["lat"])
	for _, row in df.iloc[1:].iterrows():
		# Check if you are at a new task start
		loc, dloc = get_closest_endpoint(row["lon"], row["lat"])
		if dloc < 5:  # New location is less than 5 meters away
			# new_loc = get_dock(loc["geometry"]["x"], loc["geometry"]["y"])
			new_loc = loc["geometry"]["x"], loc["geometry"]["y"]
			# if vessel.location == "":
			# 	vessel.location = vessel.lonlat_s
			# if new_loc == "":
			# 	new_loc = loc["geometry"]["x"], loc["geometry"]["y"]
			if new_loc != vessel.location:
				res.loc[len(res.index)] = [vessel.mmsi, vessel.start, row["ts"], str(vessel.location), str(new_loc), vessel.task]
				vessel.location = new_loc
				vessel.lonlat_s = row["lon"], row["lat"]
				vessel.start = row["ts"]
				vessel.task = tasks[random.choice([0, 1])]
		vessel.lonlat_t = row["lon"], row["lat"]

		# # Check if you are at a new location
		# new_loc = get_dock(row["lon"], row["lat"])
		#
		# # dd = haversine(vessel.lonlat_t[0], vessel.lonlat_t[1], row["lon"], row["lat"])
		# # delta = (row["ts"] - time) / 1000
		# # # cutoff point:
		# # if dd / delta > 6:
		# # 	print("Weird velocity:", dd, delta, dd/delta)
		#
		# if new_loc != vessel.location:
		# 	# fix for teleportation issue
		# 	# add intermediate points on which dock/sailing transition is assumed
		# 	# it is assumed that these points lie on the theoretical trajectory => APPROXIMATION
		#
		# 	# path = [vessel.lonlat_t, (row["lon"], row["lat"])]
		# 	# dists = [haversine(*vessel.lonlat_t, row["lon"], row["lat"])]
		#
		# 	path, dists = pathfinder(graph, vessel.lonlat_t, (row["lon"], row["lat"]))
		# 	tot_dist = sum(dists)
		#
		# 	if in_dock and new_loc != "":
		# 		# check hidden movement to the next dock: divide the trajectory in 3 equal parts
		# 		pa1, pb1, percentage = fpp(path, dists, 1/3)
		# 		center = pa1[0] + (pb1[0] - pa1[0]) * percentage, pa1[1] + (pb1[1] - pa1[1]) * percentage
		# 		pa2, pb2, percentage = fpp(path, dists, 2/3)
		# 		p2 = pa2[0] + (pb2[0] - pa2[0]) * percentage, pa2[1] + (pb2[1] - pa2[1]) * percentage
		#
		# 		d1 = d2 = d3 = tot_dist / 3
		# 		t1 = (row["ts"] + 2 * time) / 3
		# 		t2 = (2 * row["ts"] + time) / 3
		#
		# 		# add a movement to the next dock
		# 		res.loc[len(res.index) + 1.5] = [vessel.mmsi, vessel.name, t1, t2, None,
		# 		                                 center[0], center[1], p2[0], p2[1], d3, vessel.task]
		# 	else:
		# 		# from dock to free or vice-versa: divide the trajectory in 2 equal parts
		# 		pa1, pb1, percentage = fpp(path, dists, 1 / 2)
		# 		center = p2 = pa1[0] + (pb1[0] - pa1[0]) * percentage, pa1[1] + (pb1[1] - pa1[1]) * percentage
		#
		# 		d1 = d2 = tot_dist / 2
		# 		t1 = t2 = (row["ts"] + time) / 2
		#
		# 	# store previous trajectory
		# 	res.loc[len(res.index)] = [vessel.mmsi, vessel.name, vessel.start, t1, vessel.location,
		# 	                           vessel.lonlat_s[0], vessel.lonlat_s[1],
		# 	                           center[0], center[1], vessel.distance + d1, vessel.task]
		#
		# 	if new_loc != "":
		# 		# Randomly pick tugging or sailing
		# 		task = random.choice([0, 1])
		# 		vessel.task = tasks[task]
		#
		# 	# store beginning of new trajectory
		# 	vessel.start = t2
		# 	vessel.end = -1
		# 	vessel.location = new_loc
		# 	vessel.distance = d2
		# 	vessel.lonlat_s = p2
		# 	vessel.lonlat_t = row["lon"], row["lat"]
		# else:
		# 	# find the distance between the previous point and the current point
		# 	vessel.distance += haversine(vessel.lonlat_t[0], vessel.lonlat_t[1], row["lon"], row["lat"])
		# 	vessel.lonlat_t = row["lon"], row["lat"]
		#
		# time = row["ts"]
		# in_dock = new_loc != ""
	# loc = get_dock(*vessel.lonlat_t)
	# if loc == "":
	# 	loc = vessel.lonlat_t
	# if vessel.location == "":
	# 	vessel.location = vessel.lonlat_s
	res.loc[len(res.index)] = [vessel.mmsi, vessel.start, df.iloc[-1]["ts"], str(vessel.location), str(vessel.lonlat_t), vessel.task]
	#
	# if vessel.end != -1:
	# 	res.loc[len(res.index)] = [vessel.mmsi, vessel.name, vessel.start, df.iloc[-1]["ts"], vessel.location,
	# 	                           vessel.lonlat_s[0], vessel.lonlat_s[1], vessel.lonlat_t[0], vessel.lonlat_t[1],
	# 	                           vessel.distance, vessel.task]
	# print("AVG dt:", sum(dts) / len(dts), max(dts), min(dts))
	# res.sort_values(by=["start"], inplace=True)
	# res = res.sort_index().reset_index(drop=True)
	# res["velocity"] = res["distance"] / ((res["end"] - res["start"]) / 1000)
	res.to_csv("results-de2/%s-de.csv" % str(vessel.mmsi), index=False)

if __name__ == '__main__':
	# print(get_dock(4.242435, 51.27712))
	# import sys
	# analyze(sys.argv[2])
	# analyze("results/205627000.csv")

	df = pd.DataFrame()

	TFILE = "tugs.csv"
	tugs = pd.read_csv(TFILE)
	mmsi = tugs["MMSI"].dropna().astype(np.int32)
	for idx in mmsi:
		# print("checking", idx)
		# analyze("results/%s.csv" % str(idx))
		# print(idx, "done")
		fname = "results-de2/%s-de.csv" % str(idx)
		if not exists(fname):
			print(fname, "does not exist")
			continue
		tug = pd.read_csv(fname)
		df = pd.concat([df, tug], ignore_index=True)
	df.sort_values(by=["start"], inplace=True)
	df.to_csv("results-de2/IVEF.csv", index=False)