extends Node

# Network Manager - Handles multiplayer connections and player spawning
# Supports both hosting and joining games

signal player_connected(peer_id, player_info)
signal player_disconnected(peer_id)
signal connection_failed()
signal connection_succeeded()

const DEFAULT_PORT = 7777
const MAX_PLAYERS = 8

var players_info = {} # Dictionary of peer_id -> {local_player_count: int, player_names: []}
var local_player_count = 1 # How many local players on this machine
var is_hosting = false

func _ready():
	# Connect multiplayer signals
	multiplayer.peer_connected.connect(_on_peer_connected)
	multiplayer.peer_disconnected.connect(_on_peer_disconnected)
	multiplayer.connected_to_server.connect(_on_connected_to_server)
	multiplayer.connection_failed.connect(_on_connection_failed)
	multiplayer.server_disconnected.connect(_on_server_disconnected)

func host_game(port: int = DEFAULT_PORT) -> bool:
	var peer = ENetMultiplayerPeer.new()
	var error = peer.create_server(port, MAX_PLAYERS)
	
	if error != OK:
		push_error("Failed to create server: " + str(error))
		return false
	
	multiplayer.multiplayer_peer = peer
	is_hosting = true
	
	# Register the host as a player
	var my_id = multiplayer.get_unique_id()
	players_info[my_id] = {
		"local_player_count": local_player_count,
		"player_names": _generate_player_names(local_player_count, my_id)
	}
	
	print("Server started on port ", port)
	return true

func join_game(address: String, port: int = DEFAULT_PORT) -> bool:
	var peer = ENetMultiplayerPeer.new()
	var error = peer.create_client(address, port)
	
	if error != OK:
		push_error("Failed to create client: " + str(error))
		return false
	
	multiplayer.multiplayer_peer = peer
	is_hosting = false
	
	print("Attempting to connect to ", address, ":", port)
	return true

func disconnect_from_game():
	if multiplayer.multiplayer_peer:
		multiplayer.multiplayer_peer.close()
		multiplayer.multiplayer_peer = null
	players_info.clear()
	is_hosting = false

func set_local_player_count(count: int):
	local_player_count = max(1, min(count, 4)) # Limit to 1-4 local players

func _generate_player_names(count: int, peer_id: int) -> Array:
	var names = []
	for i in range(count):
		names.append("Player%d_%d" % [peer_id, i + 1])
	return names

# Called when a peer connects to the server
func _on_peer_connected(id: int):
	print("Peer connected: ", id)

# Called when a peer disconnects
func _on_peer_disconnected(id: int):
	print("Peer disconnected: ", id)
	if players_info.has(id):
		players_info.erase(id)
	player_disconnected.emit(id)

# Called on client when successfully connected to server
func _on_connected_to_server():
	print("Successfully connected to server")
	connection_succeeded.emit()
	
	# Send our player info to the server
	var my_id = multiplayer.get_unique_id()
	_register_player.rpc_id(1, my_id, local_player_count)

# Called on client when connection fails
func _on_connection_failed():
	print("Connection failed")
	multiplayer.multiplayer_peer = null
	connection_failed.emit()

# Called on client when disconnected from server
func _on_server_disconnected():
	print("Server disconnected")
	multiplayer.multiplayer_peer = null
	players_info.clear()

# RPC to register a player with the server
@rpc("any_peer", "reliable")
func _register_player(peer_id: int, local_count: int):
	if not multiplayer.is_server():
		return
	
	players_info[peer_id] = {
		"local_player_count": local_count,
		"player_names": _generate_player_names(local_count, peer_id)
	}
	
	print("NetworkManager: Registered player ", peer_id, " with ", local_count, " local players")
	print("NetworkManager: Total players_info: ", players_info)
	
	# Sync all player info to the new client (so they know about everyone)
	_sync_players.rpc_id(peer_id, players_info)
	
	# Notify all clients (including the new one) about the new player
	_notify_player_joined.rpc(peer_id, players_info[peer_id])
	
	# Emit signal on server
	player_connected.emit(peer_id, players_info[peer_id])

# RPC to sync all player info to a newly connected client
@rpc("authority", "reliable")
func _sync_players(all_players_info: Dictionary):
	players_info = all_players_info
	print("NetworkManager: Client synced all player info: ", players_info)
	
	# Emit signals for all existing players (so game world can spawn them)
	for peer_id in players_info.keys():
		# Emit for ALL players including ourselves (game world will handle it)
		print("NetworkManager: Emitting player_connected for peer ", peer_id)
		player_connected.emit(peer_id, players_info[peer_id])

# RPC to notify all clients when a player joins
@rpc("authority", "reliable")
func _notify_player_joined(peer_id: int, player_info: Dictionary):
	print("NetworkManager: Notified about player ", peer_id, " joining")
	if not players_info.has(peer_id):
		players_info[peer_id] = player_info
	player_connected.emit(peer_id, player_info)

func get_all_player_ids() -> Array:
	return players_info.keys()

func get_player_info(peer_id: int) -> Dictionary:
	return players_info.get(peer_id, {})

