extends Node3D

@export var _player_scene: PackedScene

@export var _soundtrack: AudioStreamPlayer
@export var _players: Node3D
@export var _chat_panel: Panel
@export var _chat_input: LineEdit
@export var _chat_history_scroll: ScrollContainer
@export var _chat_history: VBoxContainer
@export var _chat_panel_inactive: Panel
@export var _chat_history_inactive: VBoxContainer
@export var _chat_history_scroll_inactive: ScrollContainer
@export var _coin_label: RichTextLabel

## Things to yet play, so to not repeat ourselves much.
const PLAYLIST: Array[String] = [
	"res://assets/musics/mod118.ogg",
	"res://assets/musics/mod147-medley.mp3",
	"res://assets/musics/mod170-toomanyfuckingdoors.ogg",
	"res://assets/musics/sho.ogg",
]
var _playlist_remaining: Array[String]


func _ready() -> void:
	print("ingame ready")
	
	_chat_history_scroll.get_v_scroll_bar().changed.connect(
		_on_chat_history_scroll_changed.bind(_chat_history_scroll)
	)
	_chat_history_scroll_inactive.get_v_scroll_bar().changed.connect(
		_on_chat_history_scroll_changed.bind(_chat_history_scroll_inactive)
	)
	
	if "--on-top" in OS.get_cmdline_args():
		get_window().grab_focus()
	
	Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
	
	if not multiplayer.is_server():
		return
	
	multiplayer.peer_connected.connect(_add_player)
	multiplayer.peer_disconnected.connect(_remove_player)
	
	for id in multiplayer.get_peers():
		_add_player.call_deferred(id)
	
	if not OS.has_feature("dedicated_server"):
		_add_player.call_deferred(1)

	if not "--join" in OS.get_cmdline_args():
		_soundtrack.finished.connect(_play_new_track)
		_play_new_track()

# TODO: sync what's played for peers, server controlled
func _play_new_track():
	if _playlist_remaining.size() == 0:
		_playlist_remaining = PLAYLIST.duplicate()
	var selection = _playlist_remaining.pick_random()
	_playlist_remaining.erase(selection)
	_soundtrack.stream = load(selection)
	_soundtrack.play()


func _exit_tree() -> void:
	if not multiplayer.is_server():
		return
	
	multiplayer.peer_connected.disconnect(_add_player)
	multiplayer.peer_disconnected.disconnect(_remove_player)


func _unhandled_input(event: InputEvent) -> void:
	if event.is_action_pressed("chat"):
		get_viewport().set_input_as_handled()
		_activate_chat()


func _input(event: InputEvent) -> void:
	if event.is_action_pressed("ui_cancel"):
		get_viewport().set_input_as_handled()
		_deactivate_chat()


func _process(_delta: float) -> void:
	# this is fine but should this be done in response to a signal instead?
	_coin_label.text = "COINS: %d" % GameState.fetch().coins


func _activate_chat() -> void:
	_chat_panel.show()
	_chat_panel_inactive.hide()
	_chat_input.grab_focus.call_deferred()
	_players.get_node(str(multiplayer.get_unique_id())).controls_disabled = true
	Input.mouse_mode = Input.MOUSE_MODE_VISIBLE


func _deactivate_chat() -> void:
	_chat_panel.hide()
	_chat_panel_inactive.show()
	_players.get_node(str(multiplayer.get_unique_id())).controls_disabled = false
	Input.mouse_mode = Input.MOUSE_MODE_CAPTURED


func _add_player(id: int) -> void:
	print("add player %d" % id)
	var character: Player = _player_scene.instantiate()
	character.id = id
	character.name = str(id)
	_players.add_child(character, true)
	_set_character_authority.rpc(id)


func _remove_player(id: int) -> void:
	if not _players.has_node(str(id)):
		return
	
	print("remove player %d" % id)
	_players.get_node(str(id)).queue_free()


@rpc("authority", "call_local", "reliable")
func _set_character_authority(id: int) -> void:
	if not _players.has_node(str(id)):
		return
	
	_players.get_node(str(id)).set_multiplayer_authority(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:
	_chat_history.add_child(_make_chat_message(username, text))
	_chat_history_inactive.add_child(_make_chat_message(username, text))


func _on_chat_history_scroll_changed(history: ScrollContainer) -> void:
	# keep history scrolled to the bottom
	history.scroll_vertical = int(history.get_v_scroll_bar().max_value)


func _make_chat_message(username: String, text: String) -> RichTextLabel:
	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]")])
	return label


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