extends Node

# Player Manager - Handles spawning and managing all players (local and remote)

@export var player_scene: PackedScene

var players = {} # Dictionary of unique_player_id -> player_node
var spawn_points = [] # Array of spawn positions

func _ready():
	# Get spawn points from the level
	call_deferred("_setup_spawn_points")

func _setup_spawn_points():
	# Default spawn points in a circle
	for i in range(8):
		var angle = i * PI * 2 / 8
		var pos = Vector2(cos(angle), sin(angle)) * 200
		spawn_points.append(pos)

func spawn_players_for_peer(peer_id: int, local_count: int):
	for local_index in range(local_count):
		spawn_player(peer_id, local_index)

func spawn_player(peer_id: int, local_index: int):
	if not player_scene:
		push_error("Player scene not set!")
		return
	
	var unique_id = "%d_%d" % [peer_id, local_index]
	
	# Check if player already exists
	if players.has(unique_id):
		print("Player ", unique_id, " already exists, skipping spawn")
		return
	
	var player = player_scene.instantiate()
	
	# Set player properties
	player.name = "Player_" + unique_id
	player.peer_id = peer_id
	player.local_player_index = local_index
	player.is_local_player = (peer_id == multiplayer.get_unique_id())
	
	# Set spawn position - use a unique spawn point
	# Find the first spawn point that's not too close to existing players
	var spawn_pos = Vector2.ZERO
	if spawn_points.size() > 0:
		# Try to find a spawn point that's not occupied
		var found_spawn = false
		for i in range(spawn_points.size()):
			var candidate_pos = spawn_points[i]
			var is_free = true
			# Check if any existing player is too close
			for existing_player in players.values():
				if is_instance_valid(existing_player) and candidate_pos.distance_to(existing_player.position) < 32:
					is_free = false
					break
			if is_free:
				spawn_pos = candidate_pos
				found_spawn = true
				break
		
		# If no free spawn point found, use a random one
		if not found_spawn:
			spawn_pos = spawn_points[randi() % spawn_points.size()]
	else:
		# Fallback if no spawn points
		spawn_pos = Vector2.ZERO
	
	# CRITICAL: Verify spawn position is safe (on floor, not in wall)
	# Use game_world's safety check if available
	var game_world = get_tree().get_first_node_in_group("game_world")
	if game_world and game_world.has_method("_is_safe_spawn_position"):
		if not game_world._is_safe_spawn_position(spawn_pos):
			# Spawn position is not safe, find a nearby safe position
			if game_world.has_method("_find_nearby_safe_spawn_position"):
				var safe_pos = game_world._find_nearby_safe_spawn_position(spawn_pos, 128.0)
				print("Player ", unique_id, " spawn position ", spawn_pos, " was unsafe, using safe position: ", safe_pos)
				spawn_pos = safe_pos
			else:
				print("Player ", unique_id, " WARNING: Spawn position ", spawn_pos, " is not safe, but no safe position finder available!")
	
	player.position = spawn_pos
	
	# Set multiplayer authority BEFORE add_child so _ready() sees correct authority.
	# Otherwise joiner's player runs _ready() with default authority (e.g. server) and skips _setup_player_appearance(),
	# so joiner Wizard never gets tome_of_healing / tome_of_frostspike.
	if multiplayer.has_multiplayer_peer():
		player.set_multiplayer_authority(peer_id)
	
	# Add to YSort node for automatic Y-sorting
	var ysort = get_parent().get_node_or_null("Entities")
	if ysort:
		ysort.add_child(player)
	else:
		# Fallback to parent if YSort doesn't exist
		get_parent().add_child(player)
	
	players[unique_id] = player

func despawn_players_for_peer(peer_id: int):
	var to_remove = []
	for unique_id in players.keys():
		if unique_id.begins_with(str(peer_id) + "_"):
			to_remove.append(unique_id)
	
	for unique_id in to_remove:
		if players.has(unique_id):
			players[unique_id].queue_free()
			players.erase(unique_id)

func get_local_players() -> Array:
	var local = []
	var my_peer_id = multiplayer.get_unique_id()
	for player in players.values():
		# Check if player is still valid (not freed)
		if not is_instance_valid(player):
			continue
		if player.peer_id == my_peer_id:
			local.append(player)
	return local

func get_all_players() -> Array:
	# Filter out any freed players
	var valid_players = []
	for player in players.values():
		if is_instance_valid(player):
			valid_players.append(player)
		else:
			# Remove freed player from dictionary
			for key in players.keys():
				if players[key] == player:
					players.erase(key)
					break
	return valid_players
