extends Node

@export_category("UI")
@export var connect_ui: Control
@export var address_input: LineEdit
@export var port_input: LineEdit

func host():
	var host_dict = _parse_input()
	if host_dict.size() == 0:
		return ERR_CANT_RESOLVE

	var port = host_dict.port

	# Start host
	print("Starting host on port %s" % port)
	
	var peer = ENetMultiplayerPeer.new()
	if peer.create_server(port) != OK:
		print("Failed to listen on port %s" % port)

	get_tree().get_multiplayer().multiplayer_peer = peer
	print("Listening on port %s" % port)
	
	# Wait for server to start
	await Async.condition(
		func():
			return peer.get_connection_status() != MultiplayerPeer.CONNECTION_CONNECTING
	)

	if peer.get_connection_status() != MultiplayerPeer.CONNECTION_CONNECTED:
		OS.alert("Failed to start server!")
		return
	
	print("Server started")
	get_tree().get_multiplayer().server_relay = true
	
	connect_ui.hide()
	
	# Only start manually if NetworkEvents is not handling it (e.g. multiplayer-simple)
	if not NetworkEvents.enabled:
		NetworkTime.start()

func join():
	var host_dict = _parse_input()
	if host_dict.size() == 0:
		return ERR_CANT_RESOLVE
		
	var address = host_dict.address
	var port = host_dict.port

	# Connect
	print("Connecting to %s:%s" % [address, port])
	var peer = ENetMultiplayerPeer.new()
	var err = peer.create_client(address, port)
	if err != OK:
		OS.alert("Failed to create client, reason: %s" % error_string(err))
		return err

	get_tree().get_multiplayer().multiplayer_peer = peer
	
	# Wait for connection process to conclude
	await Async.condition(
		func():
			return peer.get_connection_status() != MultiplayerPeer.CONNECTION_CONNECTING
	)

	if peer.get_connection_status() != MultiplayerPeer.CONNECTION_CONNECTED:
		OS.alert("Failed to connect to %s:%s" % [address, port])
		return

	print("Client started")
	connect_ui.hide()
	
	# Only start manually if NetworkEvents is not handling it (e.g. multiplayer-simple)
	if not NetworkEvents.enabled:
		NetworkTime.start()

func _enter_tree():
	# Hide and show UI as appropriate
	# These handlers are necessary, since the game could have started via
	# autoconnect, or any other method
	NetworkEvents.on_client_start.connect(func(__): connect_ui.hide())
	NetworkEvents.on_server_start.connect(func(): connect_ui.hide())
	NetworkEvents.on_client_stop.connect(func(): connect_ui.show())
	NetworkEvents.on_server_stop.connect(func(): connect_ui.show())

func _parse_input() -> Dictionary:
	# Validate inputs
	var address = address_input.text
	var port = port_input.text
	
	if address == "":
		OS.alert("No host specified!")
		return {}
		
	if not port.is_valid_int():
		OS.alert("Invalid port!")
		return {}
	port = port.to_int()

	return {
		"address": address,
		"port": port
	}
