extends Node

@onready var player_scene: PackedScene = preload("res://player/Player.tscn")

var players: Array[int] = []

var steam_id: int = 0
var steam_username: String = ""
var lobby_id: int = 0
var steam_initialized: bool = false
var steam_app_id: int = 480

var peer: SteamMultiplayerPeer


func _ready() -> void:
	OS.set_environment("SteamAppId", str(steam_app_id))
	OS.set_environment("SteamGameId", str(steam_app_id))
	steam_initialized = init_steam()
	
	if not steam_initialized:
		print("!!! Steam did not initialize. Multiplayer will be disabled.")
		return
	
	Steam.lobby_created.connect(_on_lobby_created)
	Steam.lobby_joined.connect(_on_lobby_joined)
	Steam.lobby_chat_update.connect(_on_lobby_chat_update)
	Steam.p2p_session_request.connect(_on_p2p_session_request)
	Steam.join_requested.connect(_on_lobby_join_requested)
	
	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)
	
	check_command_line()
	
	multiplayer.server_relay = true


func _process(delta):
	if not steam_initialized:
		return
	Steam.run_callbacks()


func create_lobby():
	print("[HOST] 1. Attempting to create lobby...")
	Steam.createLobby(Steam.LOBBY_TYPE_FRIENDS_ONLY, 4)


func _on_lobby_created(connect: int, this_lobby_id: int):
	if connect != 1:
		print("[HOST] !!! Lobby creation failed.")
		return
		
	lobby_id = this_lobby_id
	print("[HOST] 2. Lobby created successfully (ID: %s)." % lobby_id)
	
	Steam.setLobbyJoinable(lobby_id, true)
	Steam.setLobbyData(lobby_id, "name", steam_username + "'s Lobby")
	
	setup_multiplayer_peer(true)
	print("[HOST] 3. Multiplayer host started (My Peer ID is always 1).")
	
	#players.append(peer.get)
	GameManager.request_server_to_spawn_player.rpc_id(1, 1, steam_username)


func join_lobby(this_lobby_id: int):
	print("[CLIENT] 1. Attempting to join lobby (ID: %s)..." % this_lobby_id)
	Steam.joinLobby(this_lobby_id)


func _on_lobby_join_requested(this_lobby_id: int, friend_id: int) -> void:
	print("[CLIENT] 1. Attempting to join lobby (ID: %s)..." % this_lobby_id)
	join_lobby(this_lobby_id)


func _on_lobby_joined(this_lobby_id: int, _p, _l, response: int):
	if response != Steam.CHAT_ROOM_ENTER_RESPONSE_SUCCESS:
		print("[CLIENT] !!! Failed to join lobby: %s" % get_join_fail_reason(response))
		return

	lobby_id = this_lobby_id
	print("[CLIENT] 2. Successfully joined Steam lobby.")
	
	if Steam.getLobbyOwner(lobby_id) != steam_id:
		print("[CLIENT] 3. I am a client, creating multiplayer peer to connect to host.")
		setup_multiplayer_peer(false)


func _on_connected_to_server():
	print("[CLIENT] 4. Successfully connected to host's multiplayer peer.")
	print("[CLIENT] 5. Sending my info to the server for registration...")
	GameManager.request_server_to_spawn_player.rpc_id(1, multiplayer.get_unique_id(), steam_username)


func _on_p2p_session_request(steam_id_remote: int) -> void:
	print("[P2P] ==> Session request from: %s. Accepting." % steam_id_remote)
	Steam.acceptP2PSessionWithUser(steam_id_remote)


func init_steam() -> bool:
	var response: Dictionary = Steam.steamInitEx()
	if response['status'] > 0:
		print("!!! Failed to init steam! Code: %s " % response)
		return false
	steam_id = Steam.getSteamID()
	steam_username = Steam.getPersonaName()
	print("Steam initialized successfully for %s (ID: %s)." % [steam_username, steam_id])
	return true


func setup_multiplayer_peer(is_host: bool = false) -> void:
	if multiplayer.multiplayer_peer and multiplayer.multiplayer_peer.get_connection_status() != MultiplayerPeer.CONNECTION_DISCONNECTED:
		multiplayer.multiplayer_peer.close()

	peer = SteamMultiplayerPeer.new()
	
	if is_host:
		peer.create_host(0)
	else:
		var host_id = Steam.getLobbyOwner(lobby_id)
		peer.create_client(host_id, 0)
	
	multiplayer.multiplayer_peer = peer


func _on_peer_connected(id: int):
	print("[INFO] Peer %s has established a multiplayer session." % id)
	#players.append()


func _on_peer_disconnected(id: int):
	print("[INFO] Peer %s has disconnected." % id)
	if players.has(id):
		#players[id].queue_free()
		players.erase(id)


func _on_connection_failed() -> void:
	print("[CLIENT] !!! Connection to the host failed.")


func _on_lobby_chat_update(_l_id, user_changed_id: int, _u_m_c_id, chat_state: int):
	var state_string = "UNKNOWN"
	match chat_state:
		Steam.CHAT_MEMBER_STATE_CHANGE_ENTERED: state_string = "ENTERED"
		Steam.CHAT_MEMBER_STATE_CHANGE_LEFT: state_string = "LEFT"
		Steam.CHAT_MEMBER_STATE_CHANGE_DISCONNECTED: state_string = "DISCONNECTED"
	print("[LOBBY INFO] User %s has %s the lobby." % [user_changed_id, state_string])


func check_command_line() -> void:
	var args: Array = OS.get_cmdline_args()
	if args.size() > 1 and args[0] == "+connect_lobby":
		if int(args[1]) > 0:
			print("[CMD] Command line join request for lobby ID: %s" % args[1])
			join_lobby(int(args[1]))


func get_join_fail_reason(response: int) -> String:
	match response:
		1: return "Doesnt Exist"
		2: return "Not Allowed"
		3: return "Full"
		4: return "Error"
		5: return "Banned"
		6: return "Limited"
		7: return "Clan Disabled"
		8: return "Community Ban"
		9: return "Member Blocked You"
		10: return "You Blocked Member"
		_: return "Unknown Reason"
