extends CanvasLayer

# Game UI - Main menu and multiplayer lobby

@onready var main_menu = $Control/MainMenu
@onready var host_button = $Control/MainMenu/VBoxContainer/HostButton
@onready var join_button = $Control/MainMenu/VBoxContainer/JoinButton
@onready var select_race_button = $Control/MainMenu/VBoxContainer/SelectRaceButton
@onready var network_mode_option = $Control/MainMenu/VBoxContainer/NetworkModeContainer/NetworkModeOption
@onready var network_mode_container = $Control/MainMenu/VBoxContainer/NetworkModeContainer
@onready var local_players_spinbox = $Control/MainMenu/VBoxContainer/LocalPlayersContainer/SpinBox
@onready var address_input = $Control/MainMenu/VBoxContainer/AddressContainer/AddressInput
@onready var room_fetch_status_container = $Control/MainMenu/VBoxContainer/RoomFetchStatusContainer
@onready var loading_label = $Control/MainMenu/VBoxContainer/RoomFetchStatusContainer/RoomFetchLoadingContainer/LoadingLabel
@onready var loading_spinner = $Control/MainMenu/VBoxContainer/RoomFetchStatusContainer/RoomFetchLoadingContainer/LoadingSpinner
@onready var last_fetch_label = $Control/MainMenu/VBoxContainer/RoomFetchStatusContainer/LastFetchLabel

@onready var network_manager = $"/root/NetworkManager"

var select_class_scene: PackedScene = preload("res://scenes/select_class.tscn")
var select_class_instance: Node = null # Race select overlay (before dungeon)
var _race_select_standalone: bool = false # True when joiner picks race before Join (don't start game on confirm)
var pending_auto_join_after_race_select: bool = false # --join --webrtc with no --race=: show race select first, then auto-join

var connection_error_label: Label = null
var connection_error_shown: bool = false # Prevent spamming error messages
var is_joining_attempt: bool = false
var last_join_address: String = ""
var room_fetch_timer: Timer = null # Timer for retrying room fetches
var is_auto_joining: bool = false # Track if we're in auto-join mode
var is_hosting: bool = false # Track if we're hosting (don't fetch rooms when hosting)
var room_list_container: VBoxContainer = null # Container for displaying available rooms
var refresh_button: Button = null # Refresh button for manually reloading rooms
var refresh_cooldown_timer: Timer = null # Timer for refresh button cooldown
var active_room_join_button: Button = null # Join button we're currently using (reset on fail)

func _ready():
	# Wait for nodes to be ready
	await get_tree().process_frame
	
	# Debug: Print node paths (UI category - disabled by default for network debugging)
	LogManager.log("GameUI _ready() called", LogManager.CATEGORY_UI)
	LogManager.log("Main menu node: " + str(main_menu), LogManager.CATEGORY_UI)
	LogManager.log("Host button node: " + str(host_button), LogManager.CATEGORY_UI)
	LogManager.log("Join button node: " + str(join_button), LogManager.CATEGORY_UI)
	
	# Verify nodes exist
	if not host_button:
		push_error("host_button is null! Check node path: $Control/MainMenu/VBoxContainer/HostButton")
		return
	if not join_button:
		push_error("join_button is null! Check node path: $Control/MainMenu/VBoxContainer/JoinButton")
		return
	
	# Connect buttons
	host_button.pressed.connect(_on_host_pressed)
	join_button.pressed.connect(_on_join_pressed)
	if select_race_button:
		select_race_button.pressed.connect(_on_select_race_pressed)
	
	# Setup network mode dropdown
	if network_mode_option:
		network_mode_option.item_selected.connect(_on_network_mode_changed)
		
		# On web builds, filter out ENet option (only WebRTC and WebSocket available)
		if OS.get_name() == "Web":
			LogManager.log("GameUI: Web platform detected, filtering network mode options", LogManager.CATEGORY_UI)
			# Remove ENet option (index 0) for web builds
			network_mode_option.remove_item(0)
			# Adjust selected index (was 0 for ENet, now 0 is WebRTC)
			network_mode_option.selected = 0
			# Update network manager to use WebRTC by default
			network_manager.set_network_mode(1)
		else:
			# On native builds, default to ENet (index 0)
			network_mode_option.selected = 0
			network_manager.set_network_mode(0)
		
		# Update address input placeholder based on initial mode
		_on_network_mode_changed(network_mode_option.selected)
	
	# Connect network signals
	if network_manager:
		network_manager.connection_succeeded.connect(_on_connection_succeeded)
		network_manager.connection_failed.connect(_on_connection_failed)
		# Connect to rooms_fetched for displaying rooms (non-auto-join mode)
		if not network_manager.rooms_fetched.is_connected(_on_rooms_fetched_display):
			network_manager.rooms_fetched.connect(_on_rooms_fetched_display)
	else:
		push_error("NetworkManager not found!")
	
	# Check for command-line arguments
	_check_command_line_args()
	
	# If WebRTC is selected at startup (not auto-joining and not hosting), fetch rooms
	if not is_auto_joining and not is_hosting:
		var current_mode = network_manager.network_mode
		if current_mode == 1: # WebRTC
			_start_room_fetch()

func _check_command_line_args():
	var args = OS.get_cmdline_args()
	LogManager.log("GameUI: Parsing command-line arguments: " + str(args), LogManager.CATEGORY_UI)
	
	# Parse arguments
	var should_host = false
	var should_join = false
	var should_debug = false
	var force_webrtc = false
	var join_address = "" # Empty by default - will fetch rooms if WebRTC/WebSocket
	var local_count = 1
	
	for arg in args:
		if arg == "--host":
			should_host = true
			LogManager.log("GameUI: Found --host argument", LogManager.CATEGORY_UI)
		elif arg == "--join":
			should_join = true
			LogManager.log("GameUI: Found --join argument", LogManager.CATEGORY_UI)
		elif arg == "--websocket" or arg == "--webrtc":
			force_webrtc = true
			LogManager.log("GameUI: Found --websocket/--webrtc argument (forcing WebSocket mode)", LogManager.CATEGORY_UI)
		elif arg == "--room-debug":
			should_debug = true
			LogManager.log("GameUI: Found --room-debug argument", LogManager.CATEGORY_UI)
		elif arg.begins_with("--address="):
			join_address = arg.split("=")[1]
		elif arg.begins_with("--players="):
			local_count = int(arg.split("=")[1])
		elif arg.begins_with("--race="):
			var race_arg = arg.split("=")[1].strip_edges().to_lower()
			var gs = get_node_or_null("/root/GameState")
			if gs:
				if race_arg == "dwarf":
					gs.selected_race = "Dwarf"
					gs.skip_race_select = true
					LogManager.log("GameUI: Race set from argument: Dwarf (skip race select)", LogManager.CATEGORY_UI)
				elif race_arg == "elf":
					gs.selected_race = "Elf"
					gs.skip_race_select = true
					LogManager.log("GameUI: Race set from argument: Elf (skip race select)", LogManager.CATEGORY_UI)
				elif race_arg == "human":
					gs.selected_race = "Human"
					gs.skip_race_select = true
					LogManager.log("GameUI: Race set from argument: Human (skip race select)", LogManager.CATEGORY_UI)
				else:
					LogManager.log("GameUI: Ignoring invalid --race=" + race_arg + " (use dwarf, elf, or human)", LogManager.CATEGORY_UI)
	
	LogManager.log("GameUI: Parsed flags - should_host: " + str(should_host) + ", should_join: " + str(should_join) + ", force_webrtc: " + str(force_webrtc) + ", should_debug: " + str(should_debug), LogManager.CATEGORY_UI)
	
	# Force WebRTC mode if --webrtc flag is present
	if force_webrtc:
		network_manager.set_network_mode(1) # WebRTC
		if network_mode_option:
			if OS.get_name() == "Web":
				network_mode_option.selected = 0 # WebRTC is first option on web
			else:
				network_mode_option.selected = 1 # WebRTC is second option on native
			_on_network_mode_changed(network_mode_option.selected)
		LogManager.log("GameUI: WebRTC mode forced via --webrtc flag", LogManager.CATEGORY_UI)
	
	# Set debug flag only if --room-debug is used with --host or --join
	if should_debug and (should_host or should_join):
		network_manager.show_room_labels = true
		LogManager.log("Debug mode enabled: room labels will be shown", LogManager.CATEGORY_UI)
	else:
		LogManager.log("GameUI: Debug mode NOT enabled - should_debug: " + str(should_debug) + ", should_host: " + str(should_host) + ", should_join: " + str(should_join), LogManager.CATEGORY_UI)
	
	# Auto-start based on arguments
	if should_host:
		is_hosting = true # Set flag so we don't fetch rooms
		LogManager.log("Auto-hosting due to --host argument", LogManager.CATEGORY_UI)
		network_manager.set_local_player_count(local_count)
		if network_manager.host_game():
			call_deferred("_show_race_select")
	elif should_join:
		# Check network mode after it's been set
		var current_mode = network_manager.network_mode
		if join_address.is_empty() and (current_mode == 1 or current_mode == 2):
			# WebRTC/WebSocket with no address: auto-join first room. If no --race=, show race select first.
			var gs = get_node_or_null("/root/GameState")
			if gs and gs.skip_race_select:
				# --race= was passed: skip race select and auto-join immediately
				LogManager.log("Auto-joining: No address provided, fetching available rooms (mode: " + str(current_mode) + ", race: " + gs.selected_race + ")...", LogManager.CATEGORY_UI)
				network_manager.set_local_player_count(local_count)
				is_auto_joining = true
				is_joining_attempt = true
				room_fetch_timer = Timer.new()
				room_fetch_timer.name = "RoomFetchTimer"
				room_fetch_timer.wait_time = 2.0
				room_fetch_timer.timeout.connect(_retry_room_fetch)
				room_fetch_timer.autostart = false
				add_child(room_fetch_timer)
				if not network_manager.rooms_fetched.is_connected(_on_rooms_fetched_auto_join):
					network_manager.rooms_fetched.connect(_on_rooms_fetched_auto_join)
				_show_room_fetch_status()
				_start_room_fetch()
			else:
				# No --race=: show race select first; after they confirm we start auto-join
				LogManager.log("Auto-join with WebRTC/WebSocket: choose race first (no --race= passed)", LogManager.CATEGORY_UI)
				pending_auto_join_after_race_select = true
				_race_select_standalone = true
				call_deferred("_show_race_select_ui")
		elif not join_address.is_empty():
			LogManager.log("Auto-joining to " + join_address + " due to --join argument", LogManager.CATEGORY_UI)
			address_input.text = join_address
			network_manager.set_local_player_count(local_count)
			if network_manager.join_game(join_address):
				# Connection callback will handle starting the game
				pass
		else:
			# ENet mode without address - need a default address
			var default_address = "127.0.0.1"
			LogManager.log("Auto-joining to " + default_address + " due to --join argument (ENet mode, no address provided)", LogManager.CATEGORY_UI)
			address_input.text = default_address
			network_manager.set_local_player_count(local_count)
			if network_manager.join_game(default_address):
				# Connection callback will handle starting the game
				pass

func _on_rooms_fetched_display(rooms: Array):
	"""Display available rooms when fetched (non-auto-join mode)"""
	# Only handle if not in auto-join mode (auto-join has its own handler)
	if is_auto_joining:
		LogManager.log("GameUI: Ignoring rooms_fetched_display - still in auto-join mode", LogManager.CATEGORY_UI)
		return # Let auto-join handler take care of it
	
	LogManager.log("GameUI: Received rooms for display: " + str(rooms.size()) + " rooms", LogManager.CATEGORY_UI)
	
	# Hide loading indicator - request completed
	_hide_loading_indicator()
	
	# Update last fetch time
	_update_last_fetch_time()
	
	# Clear existing room list
	_clear_room_list()
	
	# Display rooms if any are found
	if rooms.is_empty():
		LogManager.log("GameUI: No available rooms found", LogManager.CATEGORY_UI)
		# Keep room fetch status visible so user can see "Last fetched: ..." even with no rooms
		# Add a "No rooms available" message
		_add_room_list_header("No available rooms")
	else:
		LogManager.log("GameUI: Found " + str(rooms.size()) + " available room(s)", LogManager.CATEGORY_UI)
		# Add header
		_add_room_list_header("Available Rooms:")
		# Add each room to the list
		for room in rooms:
			var room_code = room.get("room", "")
			var players = room.get("players", 0)
			var level = room.get("level", 1)
			_add_room_item(room_code, players, level)

func _on_rooms_fetched_auto_join(rooms: Array):
	"""Auto-join the first available room when --join --webrtc is used without address"""
	if not is_auto_joining:
		return # Not in auto-join mode, ignore
	
	# Hide loading indicator - request completed
	_hide_loading_indicator()
	
	# Update last fetch time
	_update_last_fetch_time()
	
	if rooms.is_empty():
		LogManager.log("No available rooms found, will retry in 2 seconds...", LogManager.CATEGORY_UI)
		# Start timer to retry fetching
		if room_fetch_timer:
			room_fetch_timer.start()
		return
	
	# Stop retrying - we found rooms!
	if room_fetch_timer:
		room_fetch_timer.stop()
	
	# DON'T set is_auto_joining = false yet - wait until connection succeeds or fails
	# DON'T hide room fetch status UI yet - keep it visible in case join fails
	
	# Disconnect from auto-join handler (we'll connect to display handler if join fails)
	if network_manager.rooms_fetched.is_connected(_on_rooms_fetched_auto_join):
		network_manager.rooms_fetched.disconnect(_on_rooms_fetched_auto_join)
	
	# Sort rooms by player count (prefer rooms with more players, but not full)
	rooms.sort_custom(func(a, b): return a.get("players", 0) < b.get("players", 0))
	
	# Try to join the first room
	var room = rooms[0]
	var room_code = room.get("room", "")
	if room_code.is_empty():
		LogManager.log("Room code is empty, cannot join - will retry", LogManager.CATEGORY_UI)
		# Restart timer to retry
		if room_fetch_timer:
			room_fetch_timer.start()
		is_auto_joining = true
		# Reconnect to auto-join handler
		if not network_manager.rooms_fetched.is_connected(_on_rooms_fetched_auto_join):
			network_manager.rooms_fetched.connect(_on_rooms_fetched_auto_join)
		# Keep showing status UI
		return
	
	# Get local player count from spinbox (same as _on_join_pressed does)
	var local_count = int(local_players_spinbox.value)
	
	LogManager.log("Auto-joining room: " + room_code + " (players: " + str(room.get("players", 0)) + ", level: " + str(room.get("level", 1)) + ")", LogManager.CATEGORY_UI)
	address_input.text = room_code
	network_manager.set_local_player_count(local_count)
	if network_manager.join_game(room_code):
		# Connection callback will handle starting the game
		# Note: We'll hide the UI and set is_auto_joining = false in _on_connection_succeeded
		pass
	else:
		# Join failed immediately - switch to display mode
		LogManager.log("Auto-join failed immediately, switching to room browser mode", LogManager.CATEGORY_UI)
		is_auto_joining = false
		# Connect to display handler
		if not network_manager.rooms_fetched.is_connected(_on_rooms_fetched_display):
			network_manager.rooms_fetched.connect(_on_rooms_fetched_display)
		# Keep room fetch status UI visible (with refresh button)
		_show_room_fetch_status()
		# Fetch and display available rooms
		_show_loading_indicator()
		_start_room_fetch()

func _start_pending_auto_join():
	"""Start auto-join flow after user chose race (--join --webrtc with no --race=)."""
	if main_menu:
		main_menu.visible = true # Room fetch status lives inside MainMenu
	var local_count = int(local_players_spinbox.value) if local_players_spinbox else 1
	network_manager.set_local_player_count(local_count)
	is_auto_joining = true
	is_joining_attempt = true
	if not room_fetch_timer:
		room_fetch_timer = Timer.new()
		room_fetch_timer.name = "RoomFetchTimer"
		room_fetch_timer.wait_time = 2.0
		room_fetch_timer.timeout.connect(_retry_room_fetch)
		room_fetch_timer.autostart = false
		add_child(room_fetch_timer)
	if not network_manager.rooms_fetched.is_connected(_on_rooms_fetched_auto_join):
		network_manager.rooms_fetched.connect(_on_rooms_fetched_auto_join)
	_show_room_fetch_status()
	_start_room_fetch()

func _retry_room_fetch():
	"""Retry fetching available rooms"""
	if not is_auto_joining:
		if room_fetch_timer:
			room_fetch_timer.stop()
		return
	
	LogManager.log("Retrying room fetch...", LogManager.CATEGORY_UI)
	_start_room_fetch()

func _start_room_fetch():
	"""Start fetching rooms and show loading indicator"""
	# Only fetch if WebRTC mode and not hosting
	if network_manager.network_mode != 1: # Not WebRTC
		return
	
	if is_hosting or network_manager.is_hosting:
		LogManager.log("GameUI: Skipping room fetch - we are hosting", LogManager.CATEGORY_UI)
		return
	
	# Show the status container and loading indicator
	_show_room_fetch_status()
	_show_loading_indicator()
	
	# Check if a request is already in progress before starting a new one
	var fetch_result = network_manager.fetch_available_rooms()
	if not fetch_result:
		# Request failed or is already in progress - hide loading indicator
		_hide_loading_indicator()
		# Start timer to retry (only in auto-join mode)
		if is_auto_joining and room_fetch_timer:
			room_fetch_timer.start()

func _show_room_fetch_status():
	"""Show the room fetch status UI"""
	if room_fetch_status_container:
		room_fetch_status_container.visible = true
	if last_fetch_label:
		last_fetch_label.text = "Last fetched: Never"
	# Create room list container if it doesn't exist
	_create_room_list_container()
	# Create refresh button if it doesn't exist
	_create_refresh_button()

func _show_loading_indicator():
	"""Show the loading indicator"""
	if loading_label:
		loading_label.text = "Loading rooms..."
	if loading_spinner:
		loading_spinner.text = "⏳"

func _hide_loading_indicator():
	"""Hide the loading indicator"""
	if loading_label:
		loading_label.text = ""
	if loading_spinner:
		loading_spinner.text = ""

func _hide_room_fetch_status():
	"""Hide the room fetch status UI"""
	if room_fetch_status_container:
		room_fetch_status_container.visible = false

func _create_refresh_button():
	"""Create a refresh button for manually reloading the room list"""
	if refresh_button:
		return # Already exists
	
	if not room_fetch_status_container:
		return
	
	# Create HBoxContainer for refresh button (below last fetch label)
	var refresh_container = HBoxContainer.new()
	refresh_container.name = "RefreshButtonContainer"
	refresh_container.alignment = BoxContainer.ALIGNMENT_END
	
	# Create refresh button
	refresh_button = Button.new()
	refresh_button.name = "RefreshButton"
	refresh_button.text = "Refresh Rooms"
	refresh_button.pressed.connect(_on_refresh_button_pressed)
	
	refresh_container.add_child(refresh_button)
	
	# Add refresh container after LastFetchLabel (or at the end if LastFetchLabel doesn't exist)
	var last_fetch_node = room_fetch_status_container.get_node_or_null("LastFetchLabel")
	if last_fetch_node:
		var index = last_fetch_node.get_index() + 1
		room_fetch_status_container.add_child(refresh_container)
		room_fetch_status_container.move_child(refresh_container, index)
	else:
		room_fetch_status_container.add_child(refresh_container)
	
	# Create cooldown timer
	refresh_cooldown_timer = Timer.new()
	refresh_cooldown_timer.name = "RefreshCooldownTimer"
	refresh_cooldown_timer.wait_time = 5.0
	refresh_cooldown_timer.one_shot = true
	refresh_cooldown_timer.timeout.connect(_on_refresh_cooldown_finished)
	refresh_cooldown_timer.autostart = false
	add_child(refresh_cooldown_timer)

func _on_refresh_button_pressed():
	"""Handle refresh button click"""
	LogManager.log("GameUI: Refresh button pressed", LogManager.CATEGORY_UI)
	
	# CRITICAL: Ensure we're not in auto-join mode when refreshing manually
	# This prevents _on_rooms_fetched_display from ignoring the signal
	if is_auto_joining:
		LogManager.log("GameUI: Switching from auto-join to display mode for refresh", LogManager.CATEGORY_UI)
		is_auto_joining = false
		# Stop auto-join timer if it's running
		if room_fetch_timer:
			room_fetch_timer.stop()
		# Disconnect auto-join handler
		if network_manager and network_manager.rooms_fetched.is_connected(_on_rooms_fetched_auto_join):
			network_manager.rooms_fetched.disconnect(_on_rooms_fetched_auto_join)
	
	# Ensure display handler is connected (in case it was disconnected)
	if network_manager and not network_manager.rooms_fetched.is_connected(_on_rooms_fetched_display):
		LogManager.log("GameUI: Reconnecting rooms_fetched signal to display handler", LogManager.CATEGORY_UI)
		network_manager.rooms_fetched.connect(_on_rooms_fetched_display)
	
	# Disable button and start cooldown
	if refresh_button:
		refresh_button.disabled = true
		refresh_button.text = "Refreshing..."
	
	if refresh_cooldown_timer:
		refresh_cooldown_timer.start()
	
	# Fetch rooms
	_start_room_fetch()

func _on_refresh_cooldown_finished():
	"""Re-enable refresh button after cooldown"""
	if refresh_button:
		refresh_button.disabled = false
		refresh_button.text = "Refresh Rooms"

func _update_last_fetch_time():
	"""Update the last fetch time label with current datetime"""
	# Try to find the label if it's null (might not be ready yet)
	if not last_fetch_label:
		last_fetch_label = get_node_or_null("Control/MainMenu/VBoxContainer/RoomFetchStatusContainer/LastFetchLabel")
	
	if last_fetch_label:
		var now = Time.get_datetime_dict_from_system()
		var time_str = "%02d:%02d:%02d" % [now.hour, now.minute, now.second]
		last_fetch_label.text = "Last fetched: " + time_str
		LogManager.log("GameUI: Updated last fetch time to: " + time_str, LogManager.CATEGORY_UI)
	else:
		LogManager.log_error("GameUI: Cannot update last fetch time - last_fetch_label is null!")

func _create_room_list_container():
	"""Create the container for displaying available rooms"""
	if room_list_container:
		return # Already exists
	
	if not room_fetch_status_container:
		return
	
	# Create a ScrollContainer for the room list
	var scroll_container = ScrollContainer.new()
	scroll_container.name = "RoomListScrollContainer"
	scroll_container.custom_minimum_size = Vector2(0, 150) # Set a reasonable height
	scroll_container.size_flags_horizontal = Control.SIZE_EXPAND_FILL
	
	# Create VBoxContainer inside scroll container
	room_list_container = VBoxContainer.new()
	room_list_container.name = "RoomListContainer"
	room_list_container.size_flags_horizontal = Control.SIZE_EXPAND_FILL
	
	scroll_container.add_child(room_list_container)
	
	# Add scroll container to room_fetch_status_container (after LastFetchLabel)
	room_fetch_status_container.add_child(scroll_container)

func _clear_room_list():
	"""Clear all room items from the list"""
	if room_list_container:
		for child in room_list_container.get_children():
			child.queue_free()

func _add_room_list_header(text: String):
	"""Add a header label to the room list"""
	if not room_list_container:
		_create_room_list_container()
		if not room_list_container:
			return
	
	var label = Label.new()
	label.text = text
	label.add_theme_font_size_override("font_size", 14)
	room_list_container.add_child(label)

func _add_room_item(room_code: String, players: int, level: int):
	"""Add a room item with join button to the list"""
	if not room_list_container:
		_create_room_list_container()
		if not room_list_container:
			return
	
	# Create HBoxContainer for this room
	var room_row = HBoxContainer.new()
	room_row.name = "RoomRow_" + room_code
	
	# Room code label
	var code_label = Label.new()
	code_label.text = room_code
	code_label.custom_minimum_size = Vector2(100, 0)
	code_label.add_theme_font_size_override("font_size", 12)
	room_row.add_child(code_label)
	
	# Info label (players, level)
	var info_label = Label.new()
	info_label.text = "Players: %d | Level: %d" % [players, level]
	info_label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
	info_label.add_theme_font_size_override("font_size", 12)
	room_row.add_child(info_label)
	
	# Join button
	var room_join_button = Button.new()
	room_join_button.name = "JoinButton"
	room_join_button.text = "Join"
	room_join_button.custom_minimum_size = Vector2(80, 0)
	room_join_button.pressed.connect(func(): _join_room(room_code, room_join_button))
	room_row.add_child(room_join_button)
	
	room_list_container.add_child(room_row)

func _disable_all_room_join_buttons():
	"""Disable all room Join buttons to prevent multiple clicks"""
	if not room_list_container:
		return
	for row in room_list_container.get_children():
		if row.name.begins_with("RoomRow_"):
			var btn = row.get_node_or_null("JoinButton")
			if btn and is_instance_valid(btn):
				btn.disabled = true

func _reset_room_join_buttons():
	"""Re-enable all room Join buttons and restore 'Join' text"""
	if not room_list_container:
		return
	for row in room_list_container.get_children():
		if row.name.begins_with("RoomRow_"):
			var btn = row.get_node_or_null("JoinButton")
			if btn and is_instance_valid(btn):
				btn.disabled = false
				btn.text = "Join"
	active_room_join_button = null

func _join_room(room_code: String, room_join_button: Button = null):
	"""Join a room by setting the address and clicking join"""
	if room_code.is_empty():
		return
	
	# Prevent multiple clicks: disable all join buttons and show loader state
	_disable_all_room_join_buttons()
	if room_join_button and is_instance_valid(room_join_button):
		room_join_button.text = "Joining..."
		active_room_join_button = room_join_button
	
	# Set the address input
	if address_input:
		address_input.text = room_code
	
	# Get local player count
	var local_count = int(local_players_spinbox.value)
	network_manager.set_local_player_count(local_count)
	
	is_joining_attempt = true
	last_join_address = room_code
	
	# Join the game
	if not network_manager.join_game(room_code):
		_reset_room_join_buttons()
		is_joining_attempt = false
		return
	LogManager.log("Joining room: " + room_code, LogManager.CATEGORY_UI)

func _on_network_mode_changed(index: int):
	# On web builds, index 0 = WebRTC, index 1 = WebSocket
	# On native builds, index 0 = ENet, index 1 = WebRTC, index 2 = WebSocket
	var actual_mode: int
	if OS.get_name() == "Web":
		# Web builds: 0 = WebRTC, 1 = WebSocket
		actual_mode = index + 1 # Map 0->1 (WebRTC), 1->2 (WebSocket)
	else:
		# Native builds: 0 = ENet, 1 = WebRTC, 2 = WebSocket
		actual_mode = index
	
	network_manager.set_network_mode(actual_mode)
	
	# Update address input placeholder based on mode
	if address_input:
		match actual_mode:
			0: # ENet
				address_input.placeholder_text = "Server IP or domain"
			1: # WebRTC
				address_input.placeholder_text = "Enter Room Code (e.g., ABC123)"
			2: # WebSocket
				address_input.placeholder_text = "Enter Room Code (e.g., ABC123)"
	
	var mode_names = ["ENet", "WebRTC", "WebSocket"]
	LogManager.log("GameUI: Network mode changed to: " + mode_names[actual_mode], LogManager.CATEGORY_UI)
	
	# Handle room fetching based on mode
	if actual_mode == 1: # WebRTC mode
		# Only fetch if not auto-joining and not hosting
		if not is_auto_joining and not is_hosting and not network_manager.is_hosting:
			LogManager.log("GameUI: Switched to WebRTC mode, fetching rooms", LogManager.CATEGORY_UI)
			# Ensure display handler is connected
			if network_manager and not network_manager.rooms_fetched.is_connected(_on_rooms_fetched_display):
				network_manager.rooms_fetched.connect(_on_rooms_fetched_display)
			# Show room fetch status UI (with refresh button)
			_show_room_fetch_status()
			# Fetch rooms
			_start_room_fetch()
		else:
			LogManager.log("GameUI: Switched to WebRTC mode but skipping room fetch (auto_joining: " + str(is_auto_joining) + ", hosting: " + str(is_hosting) + ")", LogManager.CATEGORY_UI)
	else: # Not WebRTC mode (ENet or WebSocket)
		# Hide room fetch status if switching away from WebRTC
		LogManager.log("GameUI: Switched away from WebRTC mode, hiding room fetch UI", LogManager.CATEGORY_UI)
		_hide_room_fetch_status()

func _on_host_pressed():
	is_hosting = true # Set flag so we don't fetch rooms
	var local_count = int(local_players_spinbox.value)
	network_manager.set_local_player_count(local_count)
	
	if network_manager.host_game():
		var mode = network_manager.network_mode
		if mode == 1 or mode == 2: # WebRTC or WebSocket
			var room_id = network_manager.get_room_id()
			var mode_name = "WebRTC" if mode == 1 else "WebSocket"
			print("Hosting ", mode_name, " game - Room Code: ", room_id)
			print("Share this code with players!")
		else:
			print("Hosting ENet game with ", local_count, " local players")
		_show_race_select()

func _on_join_pressed():
	# Reset error state when attempting new connection
	connection_error_shown = false
	_hide_connection_error()
	is_joining_attempt = true
	var address = address_input.text
	if address.is_empty():
		var mode = network_manager.network_mode
		if mode == 1 or mode == 2: # WebRTC or WebSocket
			LogManager.log("Error: Please enter a room code", LogManager.CATEGORY_UI)
			return
		else: # ENet mode without address - use default
			address = "127.0.0.1"
	
	var local_count = int(local_players_spinbox.value)
	network_manager.set_local_player_count(local_count)
	
	if network_manager.join_game(address):
		last_join_address = address
		var mode = network_manager.network_mode
		if mode == 1: # WebRTC
			LogManager.log("Joining WebRTC game with room code: " + address, LogManager.CATEGORY_UI)
		elif mode == 2: # WebSocket
			LogManager.log("Joining WebSocket game with room code: " + address, LogManager.CATEGORY_UI)
		else: # ENet
			LogManager.log("Joining ENet game at " + address + " with " + str(local_count) + " local players", LogManager.CATEGORY_UI)

func _on_connection_succeeded():
	LogManager.log("GameUI: Connection succeeded signal received, starting game", LogManager.CATEGORY_UI)
	is_joining_attempt = false
	
	# If we were in auto-join mode, now we can safely exit it
	if is_auto_joining:
		is_auto_joining = false
		# Hide room fetch status UI since we're connecting
		_hide_room_fetch_status()
		# Disconnect from auto-join handler if still connected
		if network_manager.rooms_fetched.is_connected(_on_rooms_fetched_auto_join):
			network_manager.rooms_fetched.disconnect(_on_rooms_fetched_auto_join)
	
	# Check if node is still valid before starting game
	if not is_inside_tree():
		LogManager.log_error("GameUI: Cannot start game - node not in tree", LogManager.CATEGORY_UI)
		return
	# Joiner must load game_world immediately so host's spawn RPCs can be processed. Use race from
	# GameState (set in _on_race_selected when they picked; do not overwrite). No race select after connect.
	var gs = get_node_or_null("/root/GameState")
	if gs:
		gs.race_chosen_before_connect = false
		# Only default to Dwarf if nothing was ever set (e.g. --join --webrtc --race=elf skips UI)
		if gs.selected_race.is_empty():
			gs.selected_race = "Dwarf"
		print("GameUI: Connection succeeded, starting game - GameState.selected_race = '", gs.selected_race if gs else "Dwarf", "' (joiner will use this for their player)")
	LogManager.log("GameUI: Connection succeeded, starting game (race: " + (gs.selected_race if gs else "Dwarf") + ")", LogManager.CATEGORY_UI)
	call_deferred("_start_game")

func _on_connection_failed():
	LogManager.log("Connection failed", LogManager.CATEGORY_UI)
	# Always reset room Join buttons on failure (they may be stuck on "Joining...")
	if is_joining_attempt:
		_reset_room_join_buttons()
	if connection_error_shown:
		# Already shown, don't spam
		return
	
	connection_error_shown = true
	var mode = network_manager.network_mode
	var mode_name = "ENet"
	if mode == 1:
		mode_name = "WebRTC"
	elif mode == 2:
		mode_name = "WebSocket"
	
	# If we were in auto-join mode, switch to display mode and show rooms
	if is_auto_joining:
		LogManager.log("Connection failed during auto-join, switching to room browser mode", LogManager.CATEGORY_UI)
		is_auto_joining = false
		# Stop auto-join timer
		if room_fetch_timer:
			room_fetch_timer.stop()
		# Disconnect from auto-join handler
		if network_manager.rooms_fetched.is_connected(_on_rooms_fetched_auto_join):
			network_manager.rooms_fetched.disconnect(_on_rooms_fetched_auto_join)
		# Connect to display handler instead
		if not network_manager.rooms_fetched.is_connected(_on_rooms_fetched_display):
			network_manager.rooms_fetched.connect(_on_rooms_fetched_display)
		# Show room fetch status UI (refresh button and room list)
		_show_room_fetch_status()
		# Fetch and display available rooms
		_show_loading_indicator()
		_start_room_fetch()
		# Show error message
		_show_connection_error("Failed to auto-join room. Showing available rooms below.")
		return
	
	if is_joining_attempt:
		var code_hint = (" (" + last_join_address + ")") if not last_join_address.is_empty() else ""
		_show_connection_error("Failed to join room" + code_hint + ". Did you enter the correct code?")
		# For WebRTC, refresh signaling connection after a failed join
		if mode == 1 and network_manager and network_manager.has_method("refresh_webrtc_servers"):
			network_manager.refresh_webrtc_servers(last_join_address)
			# Show room list UI and refresh rooms after a failed WebRTC join
			_show_room_fetch_status()
			_show_loading_indicator()
			_start_room_fetch()
		# Also connect to display handler if not already connected
		if not network_manager.rooms_fetched.is_connected(_on_rooms_fetched_display):
			network_manager.rooms_fetched.connect(_on_rooms_fetched_display)
	else:
		_show_connection_error("Connection failed (" + mode_name + "). Please try again.")

func _show_connection_error(message: String):
	"""Show a temporary error message in the UI"""
	if not main_menu:
		return
	
	# Remove existing error label if any
	_hide_connection_error()
	
	# Create error label
	connection_error_label = Label.new()
	connection_error_label.name = "ConnectionErrorLabel"
	connection_error_label.text = message
	connection_error_label.modulate = Color.RED
	connection_error_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
	connection_error_label.add_theme_font_size_override("font_size", 14)
	
	# Add to main menu VBoxContainer (after the title)
	var vbox = main_menu.get_node_or_null("VBoxContainer")
	if vbox:
		# Insert after title (index 0) or at the beginning
		vbox.add_child(connection_error_label)
		vbox.move_child(connection_error_label, 1) # Move to position 1 (after title)
	
	# Auto-hide after 5 seconds
	await get_tree().create_timer(5.0).timeout
	_hide_connection_error()

func _hide_connection_error():
	"""Hide and remove the connection error label"""
	if connection_error_label:
		connection_error_label.queue_free()
		connection_error_label = null

func _on_select_race_pressed():
	"""Joiner picks race before connecting. Show race select; on confirm we just store choice and return to menu."""
	_race_select_standalone = true
	_show_race_select_ui()

func _show_race_select():
	"""Show race select before dungeon (after Host or before Join). User picks race; on confirm we start game."""
	if not is_inside_tree():
		return
	var gs = get_node_or_null("/root/GameState")
	if gs and gs.skip_race_select:
		LogManager.log("GameUI: Skipping race select (race from args: " + gs.selected_race + ")", LogManager.CATEGORY_UI)
		_start_game()
		return
	_race_select_standalone = false
	_show_race_select_ui()

func _show_race_select_ui():
	"""Show race select overlay. _race_select_standalone: true = joiner picking before Join (don't start game)."""
	if not is_inside_tree():
		return
	if select_class_instance and is_instance_valid(select_class_instance):
		return
	if main_menu:
		main_menu.visible = false
	var sel = select_class_scene.instantiate()
	add_child(sel)
	select_class_instance = sel
	if sel.has_signal("race_selected"):
		sel.race_selected.connect(_on_race_selected)
	LogManager.log("GameUI: Race select shown" + (" (choose before Join)" if _race_select_standalone else ""), LogManager.CATEGORY_UI)

func _on_race_selected(race_name: String):
	"""User confirmed race. Standalone = joiner chose before Join: store and return to menu. Else start game."""
	if select_class_instance and is_instance_valid(select_class_instance):
		select_class_instance.queue_free()
		select_class_instance = null
	# Always persist chosen race to GameState (select_class sets it too; this guarantees it from signal)
	var gs = get_node_or_null("/root/GameState")
	if gs and not race_name.is_empty():
		gs.selected_race = race_name
		LogManager.log("GameUI: JOINER PICKED race='" + race_name + "', GameState.selected_race set to '" + gs.selected_race + "'", LogManager.CATEGORY_UI)
	if _race_select_standalone:
		_race_select_standalone = false
		if gs:
			gs.race_chosen_before_connect = true
		if pending_auto_join_after_race_select:
			# --join --webrtc with no --race=: they just chose race, now start auto-join
			pending_auto_join_after_race_select = false
			_start_pending_auto_join()
			LogManager.log("GameUI: Race chosen (" + race_name + "), fetching rooms to auto-join...", LogManager.CATEGORY_UI)
		else:
			if main_menu:
				main_menu.visible = true
			LogManager.log("GameUI: Race chosen for joining (" + race_name + "). Press Join when ready.", LogManager.CATEGORY_UI)
		return
	_start_game()

func _start_game():
	# Check if node is still in the tree before trying to access get_tree()
	if not is_inside_tree():
		LogManager.log_error("GameUI: Cannot change scene - node is not in tree", LogManager.CATEGORY_UI)
		return
	
	# Disconnect network callbacks so we don't get signals on freed game_ui after scene change
	if network_manager:
		if network_manager.connection_succeeded.is_connected(_on_connection_succeeded):
			network_manager.connection_succeeded.disconnect(_on_connection_succeeded)
		if network_manager.connection_failed.is_connected(_on_connection_failed):
			network_manager.connection_failed.disconnect(_on_connection_failed)
	
	# Hide menu (and race select if still present)
	if main_menu:
		main_menu.visible = false
	if select_class_instance and is_instance_valid(select_class_instance):
		select_class_instance.queue_free()
		select_class_instance = null
	
	# Load the game scene
	var tree = get_tree()
	if tree:
		tree.change_scene_to_file("res://scenes/game_world.tscn")
	else:
		LogManager.log_error("GameUI: Cannot change scene - get_tree() is null", LogManager.CATEGORY_UI)
