extends Node

@export var _start_menu: Control
@export var _username_input: LineEdit
@export var _ip_input: LineEdit

@export var _player_list: VBoxContainer
@export var _chat_menu: Control
@export var _chat_input: LineEdit
@export var _chat_history_scroll: ScrollContainer
@export var _chat_history: VBoxContainer
@export var _start_button: Button

@export var _ingame_scene: PackedScene

var _game_started := false


func _ready() -> void:
	for arg in OS.get_cmdline_args():
		if arg == "--host":
			_on_host_button_pressed()
			return
		elif arg == "--join":
			_on_join_button_pressed()
			return

	_start_menu.show()
	_chat_menu.hide()


func _on_player_joined(id: int) -> void:
	for player_id in GameState.fetch().player_data.keys():
		var username = GameState.fetch().player_data[player_id].username
		_register_player.rpc_id(id, username)
	
	if _game_started:
		_start_game.rpc_id(id)


func _on_player_left(id: int) -> void:
	_unregister_player.rpc(id)


@rpc("any_peer", "call_local", "reliable")
func _register_player(username: String) -> void:
	var id = multiplayer.get_remote_sender_id()
	GameState.fetch().player_data[id] = PlayerData.new()
	GameState.fetch().player_data[id].username = username
	
	var list_label := RichTextLabel.new()
	list_label.bbcode_enabled = false
	list_label.fit_content = true
	list_label.text = username
	_player_list.add_child(list_label)

	if id != 1 and "--immediate-start" in OS.get_cmdline_args():
		_on_start_button_pressed()


@rpc("authority", "call_local", "reliable")
func _unregister_player(id: int) -> void:
	var labels := _player_list.get_children()
	for label: RichTextLabel in labels:
		if label.text == GameState.fetch().player_data[id].username:
			label.queue_free()
			break
	
	GameState.fetch().player_data.erase(id)


@rpc("any_peer", "call_local", "reliable", 1)
func _submit_chat_message(text: String) -> void:
	var id := multiplayer.get_remote_sender_id()
	var username: String = GameState.fetch().player_data[id].username
	_add_chat_message.rpc(username, text)


@rpc("authority", "call_local", "reliable", 1)
func _add_chat_message(username: String, text: String) -> void:
	var label := RichTextLabel.new()
	label.bbcode_enabled = true
	label.fit_content = true
	label.append_text("[color=red]%s[/color] %s" % [username.replace("[", "[lb]"), text.replace("[", "[lb]")])
	_chat_history.add_child(label)
	
	# keep chat scrolled to the bottom
	await _chat_history_scroll.get_v_scroll_bar().changed
	_chat_history_scroll.scroll_vertical = _chat_history_scroll.get_v_scroll_bar().max_value


@rpc("authority", "call_local", "reliable")
func _start_game() -> void:
	_start_menu.hide()
	_chat_menu.hide()
	_game_started = true


# START MENU #
func _on_host_button_pressed() -> void:
	var peer := ENetMultiplayerPeer.new()
	var error = peer.create_server(20106, 8, 2)
	if error != OK:
		match error:
			ERR_ALREADY_IN_USE:
				push_error("server ERR_ALREADY_IN_USE")
			ERR_CANT_CREATE:
				push_error("server ERR_CANT_CREATE")
		return
	
	multiplayer.multiplayer_peer = peer
	multiplayer.multiplayer_peer.peer_connected.connect(_on_player_joined)
	multiplayer.multiplayer_peer.peer_disconnected.connect(_on_player_left)
	
	var username := _username_input.text
	if username.is_empty():
		username = "schlorpy"
	_register_player.rpc_id(1, username)
	
	_start_button.disabled = false
	_start_menu.hide()
	_chat_menu.show()
	
	print("hosted!")


func _on_join_button_pressed() -> void:
	var peer := ENetMultiplayerPeer.new()
	
	var ip := ""
	if _ip_input.text.is_empty():
		ip = "127.0.0.1"
	else:
		ip = _ip_input.text
	
	var error = peer.create_client(ip, 20106, 2)
	
	
	if error != OK:
		match error:
			ERR_ALREADY_IN_USE:
				push_error("client ERR_ALREADY_IN_USE")
			ERR_CANT_CREATE:
				push_error("client ERR_CANT_CREATE")
		return
	
	multiplayer.multiplayer_peer = peer
	
	multiplayer.connected_to_server.connect(
		func() -> void:
			var username := _username_input.text
			if username.is_empty():
				username = "schlorpy"
			_register_player.rpc(username)
			
			_start_button.disabled = true
			_start_menu.hide()
			_chat_menu.show()
			
			print("joined!")
	)


# CHAT MENU #
func _on_start_button_pressed() -> void:
	_start_game.rpc()
	$IngameContainer.add_child.call_deferred(_ingame_scene.instantiate())


func _on_chat_message_submitted(text := "") -> void:
	if _chat_input.text.is_empty():
		return
	
	_submit_chat_message.rpc_id(1, _chat_input.text)
	_chat_input.clear()
