extends Node


const SERVER_PORT = 8080
const SERVER_IP = "127.0.0.1"
var handle : String
var id : int = 1
var players : Dictionary = {}
signal client_added(handle : String, id : int)
signal all_ready()
var player_readiness : Dictionary[int, bool] = {}
var waiting : bool = false

func become_host() -> void:
	print("Starting host!")
	
	var server_peer = ENetMultiplayerPeer.new()
	server_peer.create_server(SERVER_PORT)
	players[handle] = 1
	player_readiness[1] = false
	multiplayer.multiplayer_peer = server_peer
	id = multiplayer.get_unique_id()
	print("%s %d t" % [handle, multiplayer.get_unique_id()])
	multiplayer.peer_connected.connect(_add_player_to_game)
	multiplayer.peer_disconnected.connect(_remove_player_from_game)


func join_game(new_handle : String, ip : String = "") -> Error:
	print("Player 2 joining.")
	if ip == "":
		ip = SERVER_IP
	var client_peer = ENetMultiplayerPeer.new()
	var error = client_peer.create_client(ip, SERVER_PORT)
	multiplayer.multiplayer_peer = client_peer
	handle = new_handle
	id = multiplayer.get_unique_id()
	players[handle] = id
	player_readiness[id] = false
	if !error:
		print("%s %d" % [handle, multiplayer.get_unique_id()])
	await get_tree().create_timer(0.5).timeout
	get_handle_from_peer(1)
	return !error

func is_server() -> bool:
	return multiplayer && multiplayer.is_server()

func is_host() -> bool:
	return id == 1

func _process(delta: float) -> void:
	if waiting:
		var ready : bool = true
		for pr in player_readiness.values():
			if !pr:
				ready = false
				break
		if ready:
			all_ready.emit()
			waiting = false
			for pr in player_readiness.keys():
				player_readiness[pr] = false

func _add_player_to_game(id : int) -> void:
	print("Player %s joined the game!" % id)
	await get_tree().create_timer(0.5).timeout
	get_handle_from_peer(id)

func _remove_player_from_game(id : int) -> void:
	print("Player %s left the game!" % id)

func get_handle_from_peer(peer_id) -> void:
	rpc_id(peer_id, "report_handle_to_peer", id)

@rpc("call_local", "any_peer", "reliable")
func set_player_ready(peer_id : int) -> void:
	player_readiness[peer_id] = true

@rpc("any_peer", "call_remote")
func receive_peer_handle(peer_id, peer_handle) -> void:
	print("Player %s identified as %s!" % [peer_id, peer_handle])
	players[peer_handle] = peer_id
	player_readiness[peer_id] = false
	client_added.emit(peer_handle, peer_id)

@rpc("any_peer", "call_remote")
func report_handle_to_peer(peer_id : int) -> void:
	rpc_id(peer_id, "receive_peer_handle", multiplayer.get_unique_id(), handle)

func get_local_ip() -> String:
	var ip_address = ""
	# Get all local addresses as an Array
	var addresses: PackedStringArray = IP.get_local_addresses()

	for address in addresses:
		# Check if it is an IPv4 address and not a loopback or link-local address
		if "." in address and not address.begins_with("127.") and not address.begins_with("169.254."):
			# Filter for common private IP ranges (192.168.x.x, 10.x.x.x, 172.16-31.x.x)
			if address.begins_with("192.168.") or address.begins_with("10.") or (address.begins_with("172.") and int(address.split(".")[1]) >= 16 and int(address.split(".")[1]) <= 31):
				ip_address = address
				break # Exit the loop once a valid local IP is found

	return ip_address
