extends Node

var team_CS = {
	"spawnpoints": [],
	"members": [],
	"round_score": 0,
	"game_score": 0
}
var team_OS = {
	"spawnpoints": [],
	"members": [],
	"round_score": 0,
	"game_score": 0
}

var round_number = 0
var gamemode
var map_path
var map_root_name
var server_map

func find_class_type_by_number(number):
	var found_class
	var classtypes = GameData.server_settings["game"]["classTypes"]
	for classtype in classtypes:
		if classtypes[classtype]["number"] == number:
			found_class = classtypes[classtype].duplicate()
			break
	return found_class
	
func check_map_availability(path):
	var maps = DirAccess.open("res://scenes/maps").get_files()
	var map_name = (path.split("/")[-1]).split(".")[0]
	for map in maps:
		var checking_map_name = str(map.split(".")[0])
		if(checking_map_name == map_name):
			return true
	return false

func check_gamemode_availability(gm):
	var gamemodes = GameData.server_settings["game"]["gamemodes"].keys()
	for g in gamemodes:
		if gm == g:
			return true
	return false

func find_weapon_by_number(number):
	var found_weapon
	for weapon in GameData.server_settings["game"]["weapons"].keys():
		if (GameData.server_settings["game"]["weapons"][weapon]["number"] == number):
			found_weapon = GameData.server_settings["game"]["weapons"][weapon].duplicate()
			break
	return found_weapon

func find_playermodel_by_internal_id(internal_id):
	return server_map.get_node("player" + str(internal_id))

func reloading_complete(client_id, reloading_time):
	await get_tree().create_timer(reloading_time).timeout
	var client = Networking.clients[client_id]
	if (!client["reloading"]): # if a client has interrupted the reloading
		return
	
	var weapons_list = GameData.server_settings["game"]["weapons"]
	var current_client_weapon = client["current_weapon"]
	var current_weapon_example = weapons_list.find_key(ServerUtils.find_weapon_by_number(current_client_weapon["number"]))
	var current_weapon_settings = weapons_list[current_weapon_example]
	var to_reload = current_weapon_settings["magazine"] - current_client_weapon["magazine"]
	if (to_reload <= current_client_weapon["ammo"]):
		current_client_weapon["magazine"] += to_reload
		current_client_weapon["ammo"] -= to_reload
	else:
		current_client_weapon["magazine"] += current_client_weapon["ammo"]
		current_client_weapon["ammo"] = 0

func choose_collision_shape(target, shape_num):
	var collision_shapes:Array = []
	for s in target.get_children():
		if s is CollisionShape3D:
			collision_shapes.push_back(s)
	var shape
	for i in range(0, collision_shapes.size()):
		if i == shape_num:
			shape = collision_shapes[i]
			break
	return shape

func new_round():
	round_number += 1
	team_OS["round_score"] = 0
	team_CS["round_score"] = 0
	print("CS members " + str(team_CS["members"]))
	print("OS members " + str(team_OS["members"]))
	for member in team_CS["members"]:
		member["position"] = team_CS["spawnpoints"].pick_random().get_class_spawnpoint(abs(member["class_type"]))
		ServerUtils.find_playermodel_by_internal_id(member["internal_id"]).teleport.rpc_id(Networking.clients.find_key(member), member["position"])
	for member in team_OS["members"]:
		member["position"] = team_OS["spawnpoints"].pick_random().get_class_spawnpoint(abs(member["class_type"]))
		ServerUtils.find_playermodel_by_internal_id(member["internal_id"]).teleport.rpc_id(Networking.clients.find_key(member), member["position"])
	send_scores()

func new_game(new_map_path, new_gamemode):
	team_OS["game_score"] = 0
	team_OS["round_score"] = 0
	team_CS["game_score"] = 0
	team_CS["round_score"] = 0
	
	round_number = 0
	send_scores()
	new_map_path = map_path if (new_map_path == null) else new_map_path
	new_gamemode = gamemode if (new_gamemode == null) else new_gamemode
	await switch_map(new_map_path)
	await switch_gamemode(new_gamemode)

func check_gamemode_end_conditions():
	match gamemode:
		"TDM":
			var kills_amount_to_win = GameData.server_settings["game"]["gamemodes"]["TDM"]["kills"]
			if team_OS["round_score"] >= kills_amount_to_win:
				team_OS["game_score"] += 1
				print("OS won")
				NetUtils.send_everyone(["end_round", 1]) # 1 = os is win
				new_round()
				
			elif team_CS["round_score"] >= kills_amount_to_win:
				team_CS["game_score"] += 1
				NetUtils.send_everyone(["end_round", -1]) # -1 = cs is win
				print("CS won")
				new_round()
			send_scores()
			
func switch_map(new_map_path):
	print("Switching map to %s" % new_map_path)
	if (not ServerUtils.check_map_availability(new_map_path)):
		var default_map = GameData.server_settings["defaults"]["map"]
		print("Error. No map found. Loading default map %s" % default_map)
		new_map_path = "res://scenes/maps/%s.tscn" % default_map
		if (not ServerUtils.check_map_availability(new_map_path)):
			print("Error. Default map is not valid. Please, specify a valid map in a config file.")
			return
	map_path = new_map_path
	get_tree().change_scene_to_file(map_path)
	await get_tree().create_timer(0.1).timeout #I know that this isn't a good practice, but I didn't find anything better
	map_root_name = (map_path.split("/")[-1]).split(".")[0]
	server_map = get_tree().root.get_node(map_root_name)
	
	var spawnpoints = server_map.find_children("spawnpoint*", "" ,true)
	team_OS["spawnpoints"] = []
	team_CS["spawnpoints"] = []
	for spawnpoint in spawnpoints:
		if spawnpoint.team == 0: # cs
			team_CS["spawnpoints"].push_back(spawnpoint)
		elif spawnpoint.team > 0: # os
			team_OS["spawnpoints"].push_back(spawnpoint)
	
func send_scores():
	NetUtils.send_everyone(["update_round_status", {
		"cs_round_score" = team_CS["round_score"],
		"os_round_score" = team_OS["round_score"],
		"os_game_score" = team_OS["game_score"],
		"cs_game_score" = team_CS["game_score"],
		"round_number" = round_number,
	}])

func switch_gamemode(new_gamemode):
	if not ServerUtils.check_gamemode_availability(new_gamemode):
		print("No gamemode found")
		return
	gamemode = new_gamemode

func parse_arguments():
	var arguments = {}
	for argument in OS.get_cmdline_args():
		if argument.find("=") > -1:
			var key_value = argument.split("=")
			arguments[key_value[0].lstrip("--")] = key_value[1]
		else:
			# Options without an argument will be present in the dictionary,
			# with the value set to an empty string.
			arguments[argument.lstrip("--")] = ""
	return arguments

func setup_server():
	var arguments = parse_arguments()
	
	GameData.read_settings()
	
	################ parsing map
	var path = "res://scenes/maps/%s.tscn" % arguments["map"] if arguments.has("map") else "res://scenes/maps/%s.tscn" % GameData.server_settings["defaults"]["map"]
	if (ServerUtils.check_map_availability(path)):
		map_path = path
	else:
		print("Unknown map %s Available maps:" % path)
		for map in DirAccess.open("res://scenes/maps").get_files():
			print(str(map.split(".")[0]))
		get_tree().quit()
		return
	################ parsing gamemode
	var gm = str(arguments["gamemode"]) if (arguments.has("gamemode")) else "TDM"
	if (ServerUtils.check_gamemode_availability(gm)):
		print("Gamemode exists")
	else:
		print("No")
	
	await new_game(map_path, gm)
	
	var spectator = preload("res://scenes/models/spectator.tscn").instantiate()
	server_map.add_child(spectator)
	
	Networking.StartServer()
		
func _ready():
	if "--server" in OS.get_cmdline_args():
		setup_server()
