extends Control

class_name GameUI

enum ServerMenuItem {
	ServerInfo
}

enum PopupName {
	SpaceMap,
	EnergyUsage
}

onready var logs := $Logs
onready var inspect_box := $InspectBox as RichTextLabel
onready var item_slots_container := $ItemSlots

onready var map_popup := $MapPopup
onready var sever_info_popup := $ServerInfoPopup

onready var scene := $"/root/scene"
onready var netgame := $"/root/Multiplayer"

const ItemBox := preload("res://Scenes/UI/Items/ItemBox.tscn")
var left_selected: Node = null
var right_selected: Node = null

const WHISPER_RADIUS := 32*3
const CHAT_RADIUS := 32*10
const SHOUT_RADIUS := 32*14

var inspect_mode := false
var current_inspecting = null

func _ready() -> void:
	# Add options to menu buttons
	var serverMenu := ($Menu/Margins/Grid/Server as MenuButton).get_popup()
	serverMenu.connect("id_pressed", self, "_server_option_chosen")
	serverMenu.add_item("Server info", ServerMenuItem.ServerInfo)
	
	# Create item slots
	for slot_id in range(4):
		var item_slot := ItemBox.instance()

		# By default, slot 2/3 are L/R, and 2 is selected
		match slot_id:
			1:
				item_slot.selected = true
				item_slot.current_hand = UIItemBox.CurrentHand.Left
				left_selected = item_slot
			2:
				item_slot.current_hand = UIItemBox.CurrentHand.Right
				right_selected = item_slot

		# Connect signals
		item_slot.connect("selected", self, "_itembox_selected", [item_slot])
		item_slot.connect("used_in_hand", self, "_itembox_used", [item_slot])

		item_slots_container.add_child(item_slot)

func _physics_process(_delta: float) -> void:
	if inspect_mode:
		var mouse_pos: Vector2 = scene.world.get_local_mouse_position() * scene.world.scale
		var results = scene.physics.intersect_point(mouse_pos, 1, [], 2)
		if results.size() > 0:
			var obj = results[0].collider
			if obj != current_inspecting:
				current_inspecting = obj
				if obj.has_method("inspect"):
					var data = obj.inspect()
					inspect_box.bbcode_text = ""
					inspect_box.rect_size.y = 0
					if "object_name" in obj and obj.object_name != "":
						inspect_box.append_bbcode("[b]%s[/b] (%s)" % [obj.object_name, data.type])
					else:
						inspect_box.append_bbcode("A [b]%s[/b]" % data.type)
					if "description" in data:
						inspect_box.append_bbcode("\n" + data.description)
					if "interaction" in data:
						inspect_box.append_bbcode("\n\n[i]%s[/i]" % data.interaction)
				inspect_box.visible = true
		else:
			current_inspecting = null
			inspect_box.visible = false

func _server_option_chosen(id) -> void:
	match id:
		ServerMenuItem.ServerInfo:
			$ServerInfoPopup.popup_centered()

func open_popup(popup_name) -> void:
	match popup_name:
		PopupName.SpaceMap:
			$MapPopup.popup_centered_ratio()
		PopupName.EnergyUsage:
			pass

func close_popup(popup_name) -> void:
	match popup_name:
		PopupName.SpaceMap:
			$MapPopup.visible = false
		PopupName.EnergyUsage:
			pass

const say_format = "%s says \"%s\"\n"
const ask_format = "%s asks \"%s\"\n"
const shout_format = "%s shouts \"[b]%s[/b]\"\n"
const whisper_format = "[i]%s whispers \"%s\"[/i]\n"
func _send_chat(text: String) -> void:
	var escaped_text = text.replace("[", "[\u8203").strip_edges() # Hacky way to escape BBCode
	if text.ends_with("?"):
		scene.rpc("broadcast_zone", ask_format % [netgame.player_name, escaped_text], scene.world.player.global_position, SHOUT_RADIUS)
	if text.ends_with("!!"):
		scene.rpc("broadcast_zone", shout_format % [netgame.player_name, escaped_text], scene.world.player.global_position, SHOUT_RADIUS)
	elif text.begins_with("#"):
		scene.rpc("broadcast_zone", whisper_format % [netgame.player_name, escaped_text.substr(1)], scene.world.player.global_position, WHISPER_RADIUS)
	else:
		scene.rpc("broadcast_zone", say_format % [netgame.player_name, escaped_text], scene.world.player.global_position, CHAT_RADIUS)

var inspect_offset = Vector2(20, 20)
func set_inspect(active: bool) -> void:
	inspect_box.visible = inspect_box.visible and active
	inspect_mode = active
	inspect_box.rect_global_position = get_viewport().get_mouse_position() + inspect_offset

func _input(event: InputEvent) -> void:
	var no_popups = not check_popups()
	if event.is_action_released("inspect"):
		set_inspect(false)
	elif event.is_action_pressed("inspect"):
		set_inspect(true)
	elif event.is_action_pressed("ui_scroll_left") and no_popups:
		select_next_box(-1, Input.is_action_pressed("alt_hand"))
	elif event.is_action_pressed("ui_scroll_right") and no_popups:
		select_next_box(1, Input.is_action_pressed("alt_hand"))
	elif event.is_action_pressed("swap_hands"):
		swap_hands()
	elif event is InputEventMouseMotion:
		var mousemotion := event as InputEventMouseMotion
		if inspect_mode:
			inspect_box.rect_global_position = mousemotion.position + inspect_offset

func _itembox_selected(hand, item_box: UIItemBox) -> void:
	left_selected.selected = false
	right_selected.selected = false
	match hand:
		UIItemBox.CurrentHand.Left:
			if item_box.current_hand != UIItemBox.CurrentHand.None:
				left_selected.current_hand = item_box.current_hand
				match item_box.current_hand:
					UIItemBox.CurrentHand.Right:
						right_selected = left_selected
			else:
				left_selected.current_hand = UIItemBox.CurrentHand.None
			left_selected = item_box
		UIItemBox.CurrentHand.Right:
			if item_box.current_hand != UIItemBox.CurrentHand.None:
				right_selected.current_hand = item_box.current_hand
				match item_box.current_hand:
					UIItemBox.CurrentHand.Left:
						left_selected = right_selected
			else:
				right_selected.current_hand = UIItemBox.CurrentHand.None
			right_selected = item_box
	item_box.selected = true
	item_box.current_hand = hand

func _itembox_used(item_box) -> void:
	pass

func check_popups() -> bool:
	return map_popup.visible or sever_info_popup.visible

func select_next_box(direction: int, right_hand: bool) -> void:
	var box := left_selected as UIItemBox
	if right_hand:
		box = right_selected
	var parent := box.get_parent()
	var child_count := parent.get_child_count()
	var index := box.get_index()
	index += direction
	if index < 0:
		index = child_count + index
	elif index >= child_count:
		index -= child_count
	var hand = UIItemBox.CurrentHand.Left
	if right_hand:
		hand = UIItemBox.CurrentHand.Right
	_itembox_selected(hand, parent.get_child(index))

func swap_hands() -> void:
	if left_selected.selected:
		_itembox_selected(UIItemBox.CurrentHand.Left, right_selected)
	else:
		_itembox_selected(UIItemBox.CurrentHand.Right, left_selected)
