# Hurry Curry! - a game about cooking
# Copyright (C) 2025 Hurry Curry! contributors
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, version 3 of the License only.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.
#
extends Menu

var server_list_item: PackedScene = preload("res://gui/menus/main/server_list_item.tscn")
var url_regex: RegEx = RegEx.new()

@onready var server_list: VBoxContainer = $side/margin/options/second/ScrollContainerCustom/ServerList
@onready var server_list_loading: Label = $side/margin/options/second/Loading
@onready var server_list_empty: Label = $side/margin/options/second/NoServers
@onready var connect_uri = $side/margin/options/second/connect/uri
@onready var server = $side/margin/options/second/server
@onready var server_control = $side/margin/options/second/server/control
@onready var server_connect = $side/margin/options/second/server/connect
@onready var editor_control = $side/margin/options/second/editor/control
@onready var editor_connect = $side/margin/options/second/editor/connect
@onready var editor_container = $side/margin/options/second/editor


func _ready():
	url_regex.compile("^(?:(ws|wss)://)?([^:]+)(?::([0-9]+))?$")
	if OS.has_feature("web"):
		server.hide()
	connect_uri.text = Profile.read("last_server_url")
	
	ServerList.update_server_list.connect(update_server_list)
	ServerList.update_loading.connect(update_server_list_loading)
	update_server_list(ServerList.current_list)
	update_server_list_loading(ServerList.loading)

	super()
	if not Profile.read("registry_asked"):
		var popup_data := MenuPopup.Data.new()
		popup_data.text = tr("c.menu.play.allow_query_registry").format([Settings.read("online.registry_url")])
		var allow_button := Button.new()
		allow_button.text = tr("c.menu.accept")
		var deny_button := Button.new()
		deny_button.text = tr("c.menu.deny")
		allow_button.pressed.connect(func(): Settings.write("online.use_registry", true))
		deny_button.pressed.connect(func(): Settings.write("online.use_registry", false))
		popup_data.buttons = [allow_button, deny_button]
		await submenu("res://gui/menus/popup.tscn", popup_data)
		Profile.write("registry_asked", true)
		Settings.save()

	ServerList.start()

func update_server_list(lists: Array[Array]):
	# Find out the index of the currently focused server in the list
	var prev_selected_idx := -1
	for i in range(server_list.get_children().size()):
		if server_list.get_child(i).button.has_focus():
			prev_selected_idx = i
			break
	
	for c in server_list.get_children():
		c.queue_free()
	
	var idx := 0
	for l in lists:
		for i in l:
			var server_item: ServerListItem = server_list_item.instantiate()
			server_list.add_child(server_item)
			# TODO: Implement fallback address correctly
			server_item.setup(i.name, roundi(i.players_online), i.version)
			server_item.button.pressed.connect(connect_to.bind(i.address[0]))
			# Focus the same server with the same index as the previously focused one
			if idx == prev_selected_idx:
				server_item.button.grab_focus()
			idx += 1
	
	if prev_selected_idx > idx:
		# Same index cannot be focused, since number of servers decreased
		if idx - 1 < 0:
			connect_uri.grab_focus()
		else:
			server_list.get_child(idx - 1).button.grab_focus()
	
	# Show message if no servers available
	server_list_empty.visible = idx == 0

func update_server_list_loading(status: bool):
	server_list_loading.visible = status

func _menu_cover(state):
	$side.visible = not state

func _on_connect_pressed():
	var url = connect_uri.text
	var result := url_regex.search(url)
	if result != null:
		if result.get_string(1) == "":
			url = "ws://" + url
		# only set default port for non-tls websocket connections
		if result.get_string(3) == "" and result.get_string(1) != "wss":
			url = url + ":27032"
		connect_uri.text = url
	Profile.write("last_server_url", url)
	connect_to(url)

func _on_quick_connect_pressed():
	if OS.has_feature("web"):
		connect_to(JavaScriptBridge.eval("""
			window.location.protocol.endsWith("s:")
			? `wss://${window.location.host}/`
			: `ws://${window.location.hostname}:27032/`
		"""))
	else:
		connect_to("wss://hurrycurry.metamuffin.org/")

func connect_to(url: String):
	print("Connecting to %s" % url)
	get_parent().replace_menu("res://gui/menus/game.tscn", url)

func _on_server_control_pressed():
	match Server.state:
		Service.State.RUNNING: Server.stop()
		Service.State.STOPPED: Server.start()
		Service.State.FAILED: Server.start()

func _on_editor_control_pressed():
	match Editor.state:
		Service.State.RUNNING: Editor.stop()
		Service.State.STOPPED: Editor.start(); Server.start()
		Service.State.FAILED: Editor.start()

func _on_server_connect_pressed():
	connect_to("ws://%s:%d" % [ServerService.connect_address(), Settings.read("server.bind_port")])

func _on_editor_connect_pressed():
	connect_to("ws://[::1]:27032/")

func _process(_delta):
	server_control.disabled = false
	server_connect.visible = Server.state == Service.State.RUNNING
	server_control.modulate = Color.WHITE
	match Server.state:
		Service.State.RUNNING:
			server_control.text = tr("c.menu.play.server_stop")
			server_control.modulate = Color.AQUAMARINE
		Service.State.TESTING:
			server_control.text = tr("c.menu.play.server_testing")
			server_control.disabled = true
		Service.State.STARTING:
			server_control.text = tr("c.menu.play.server_starting")
			server_control.disabled = true
		Service.State.STOPPED:
			server_control.text = tr("c.menu.play.server_start")
		Service.State.FAILED:
			server_control.text = tr("c.menu.play.server_failed")
			server_control.modulate = Color(1, 0.4, 0.5)
			server_control.tooltip_text = tr("c.menu.play.server_failed_tooltip")
		Service.State.UNAVAILABLE:
			server_control.text = tr("c.menu.play.server_unavailable")
			server_control.disabled = true
			server_control.tooltip_text = tr("c.menu.play.server_binary_not_found")

	editor_control.disabled = false
	editor_connect.visible = Editor.state == Service.State.RUNNING
	editor_control.modulate = Color.WHITE
	editor_container.visible = Editor.state != Service.State.UNAVAILABLE
	match Editor.state:
		Service.State.RUNNING:
			editor_control.text = tr("c.menu.play.editor_stop")
			editor_control.modulate = Color.AQUAMARINE
		Service.State.TESTING:
			editor_control.text = tr("c.menu.play.editor_testing")
			editor_control.disabled = true
		Service.State.STARTING:
			editor_control.text = tr("c.menu.play.editor_starting")
			editor_control.disabled = true
		Service.State.STOPPED:
			editor_control.text = tr("c.menu.play.editor_start")
		Service.State.FAILED:
			editor_control.text = tr("c.menu.play.editor_failed")
			editor_control.modulate = Color(1, 0.4, 0.5)
			editor_control.tooltip_text = tr("c.menu.play.server_failed_tooltip")
		Service.State.UNAVAILABLE:
			editor_control.text = tr("c.menu.play.editor_unavailable")
			editor_control.disabled = true
			editor_control.tooltip_text = tr("c.menu.play.server_binary_not_found")


func _on_uri_text_changed(new_text):
	connect_uri.modulate = Color.WHITE if url_regex.search(new_text) else Color.RED

func _on_back_pressed():
	exit()

func _menu_exit():
	ServerList.stop()
	super()
