extends Node3D

const CharacterPlaceholder := preload("res://scenes/character_placeholder.tscn")

var _local_role: String = ""
var _pending_player_name: String = ""
var _capsules: Dictionary = {}        # peer_id: int → Node3D
var _lobby_spots: Array[Marker3D] = []

const ARCHETYPES := {
	"Krieger":  {"race": "Mensch",  "class": "Krieger",  "STR": 3, "DEX": 1, "CON": 2, "INT": 0, "WIS": 0, "CHA": 0},
	"Magier":   {"race": "Elf",     "class": "Magier",   "STR":-1, "DEX": 2, "CON": 0, "INT": 4, "WIS": 2, "CHA": 1},
	"Kleriker": {"race": "Zwerg",   "class": "Kleriker", "STR": 1, "DEX": 0, "CON": 2, "INT": 1, "WIS": 3, "CHA": 0},
	"Schurke":  {"race": "Halbelf", "class": "Schurke",  "STR": 0, "DEX": 4, "CON": 1, "INT": 1, "WIS": 1, "CHA": 2},
	"Druide":   {"race": "Mensch",  "class": "Druide",   "STR": 0, "DEX": 1, "CON": 1, "INT": 1, "WIS": 3, "CHA": 0},
	"Barbar":   {"race": "Halbork", "class": "Barbar",   "STR": 4, "DEX": 2, "CON": 3, "INT":-1, "WIS": 0, "CHA":-1},
}

func _collect_char_data() -> Dictionary:
	var race_opt := $CanvasLayer/WaitPanel/CharSheet/CharGrid/RaceOption as OptionButton
	var class_opt := $CanvasLayer/WaitPanel/CharSheet/CharGrid/ClassOption as OptionButton
	return {
		"race":  race_opt.get_item_text(race_opt.selected),
		"class": class_opt.get_item_text(class_opt.selected),
		"STR": int($CanvasLayer/WaitPanel/CharSheet/ModGrid/SpinSTR.value),
		"DEX": int($CanvasLayer/WaitPanel/CharSheet/ModGrid/SpinDEX.value),
		"CON": int($CanvasLayer/WaitPanel/CharSheet/ModGrid/SpinCON.value),
		"INT": int($CanvasLayer/WaitPanel/CharSheet/ModGrid/SpinINT.value),
		"WIS": int($CanvasLayer/WaitPanel/CharSheet/ModGrid/SpinWIS.value),
		"CHA": int($CanvasLayer/WaitPanel/CharSheet/ModGrid/SpinCHA.value),
	}

func _send_char_data() -> void:
	NetworkManager.request_update_character.rpc_id(1, _collect_char_data())

func _setup_char_sheet() -> void:
	var race_opt := $CanvasLayer/WaitPanel/CharSheet/CharGrid/RaceOption as OptionButton
	var class_opt := $CanvasLayer/WaitPanel/CharSheet/CharGrid/ClassOption as OptionButton
	for race in ["Mensch", "Elf", "Zwerg", "Halbork", "Halbelf", "Tiefling"]:
		race_opt.add_item(race)
	for cls in ["Krieger", "Magier", "Kleriker", "Schurke", "Druide", "Barbar"]:
		class_opt.add_item(cls)
	for archetype_name: String in ARCHETYPES:
		var btn := $CanvasLayer/WaitPanel/CharSheet/ArchetypeRow.get_node(
				NodePath("Btn" + archetype_name)) as Button
		var preset: Dictionary = ARCHETYPES[archetype_name]
		btn.pressed.connect(func():
			var r_opt := $CanvasLayer/WaitPanel/CharSheet/CharGrid/RaceOption as OptionButton
			var c_opt := $CanvasLayer/WaitPanel/CharSheet/CharGrid/ClassOption as OptionButton
			for i in r_opt.item_count:
				if r_opt.get_item_text(i) == preset["race"]:
					r_opt.selected = i
			for i in c_opt.item_count:
				if c_opt.get_item_text(i) == preset["class"]:
					c_opt.selected = i
			for stat: String in ["STR", "DEX", "CON", "INT", "WIS", "CHA"]:
				($CanvasLayer/WaitPanel/CharSheet/ModGrid.get_node(
						NodePath("Spin" + stat)) as SpinBox).value = preset[stat]
			_send_char_data()
		)
	for spin_name: String in ["SpinSTR", "SpinDEX", "SpinCON", "SpinINT", "SpinWIS", "SpinCHA"]:
		($CanvasLayer/WaitPanel/CharSheet/ModGrid.get_node(NodePath(spin_name)) as SpinBox
				).value_changed.connect(func(_v: float): _send_char_data())
	(race_opt as OptionButton).item_selected.connect(func(_i: int): _send_char_data())
	(class_opt as OptionButton).item_selected.connect(func(_i: int): _send_char_data())


func _ready() -> void:
	$CanvasLayer/JoinPanel/RoleOption.add_item("Spieler")
	$CanvasLayer/JoinPanel/RoleOption.add_item("DM")

	$CanvasLayer/JoinPanel/JoinButton.pressed.connect(_on_join_pressed)
	$CanvasLayer/WaitPanel/StartButton.pressed.connect(_on_start_pressed)

	NetworkManager.connected_to_server.connect(_on_connected)
	NetworkManager.connection_failed.connect(_on_connection_failed)
	NetworkManager.player_joined.connect(_on_player_joined)
	NetworkManager.player_left.connect(_on_player_left)
	NetworkManager.player_list_synced.connect(_rebuild_player_list)
	_setup_char_sheet()

	_lobby_spots = [
		$LobbySpot0 as Marker3D,
		$LobbySpot1 as Marker3D,
		$LobbySpot2 as Marker3D,
		$LobbySpot3 as Marker3D,
		$LobbySpot4 as Marker3D,
	]
	NetworkManager.player_joined.connect(_on_player_joined_capsule)
	NetworkManager.player_left.connect(_on_player_left_capsule)
	if NetworkManager.has_signal("character_updated"):
		NetworkManager.character_updated.connect(_on_character_updated_capsule)


func _on_join_pressed() -> void:
	var player_name: String = ($CanvasLayer/JoinPanel/NameInput as LineEdit).text.strip_edges()
	if player_name.is_empty():
		return
	_local_role = "dm" if $CanvasLayer/JoinPanel/RoleOption.selected == 1 else "player"
	_pending_player_name = player_name
	NetworkManager.join_server("127.0.0.1", 4242)


func _on_connected() -> void:
	NetworkManager.register.rpc_id(1, _pending_player_name, _local_role)
	$CanvasLayer/JoinPanel.visible = false
	$CanvasLayer/WaitPanel.visible = true
	$CanvasLayer/WaitPanel/StartButton.visible = (_local_role == "dm")
	$CanvasLayer/WaitPanel/CharSheet.visible = true


func _exit_tree() -> void:
	NetworkManager.connected_to_server.disconnect(_on_connected)
	NetworkManager.connection_failed.disconnect(_on_connection_failed)
	NetworkManager.player_joined.disconnect(_on_player_joined)
	NetworkManager.player_left.disconnect(_on_player_left)
	NetworkManager.player_list_synced.disconnect(_rebuild_player_list)
	NetworkManager.player_joined.disconnect(_on_player_joined_capsule)
	NetworkManager.player_left.disconnect(_on_player_left_capsule)
	if NetworkManager.has_signal("character_updated") and NetworkManager.character_updated.is_connected(_on_character_updated_capsule):
		NetworkManager.character_updated.disconnect(_on_character_updated_capsule)


func _on_connection_failed() -> void:
	push_error("[Tavern] Verbindung fehlgeschlagen")
	_local_role = ""
	_pending_player_name = ""
	$CanvasLayer/JoinPanel.visible = true
	$CanvasLayer/WaitPanel.visible = false


func _on_player_joined(_peer_id: int, _player_name: String, _role: String) -> void:
	_rebuild_player_list()


func _on_player_left(_peer_id: int) -> void:
	_rebuild_player_list()


func _rebuild_player_list() -> void:
	$CanvasLayer/WaitPanel/PlayerList.clear()
	for p in NetworkManager.players.values():
		$CanvasLayer/WaitPanel/PlayerList.add_item("%s (%s)" % [p.name, p.role])


func _on_start_pressed() -> void:
	NetworkManager.request_start_game.rpc_id(1)


func _on_player_joined_capsule(peer_id: int, _player_name: String, _role: String) -> void:
	if _capsules.has(peer_id):
		return
	var spot_index := _capsules.size() % _lobby_spots.size()
	var capsule: Node3D = CharacterPlaceholder.instantiate()
	add_child(capsule)
	capsule.global_position = _lobby_spots[spot_index].global_position
	var player_data: Dictionary = NetworkManager.players.get(peer_id, {})
	capsule.set_label(player_data.get("name", "???"))
	capsule.set_color(player_data.get("char", {}).get("class", ""))
	_capsules[peer_id] = capsule


func _on_player_left_capsule(peer_id: int) -> void:
	if not _capsules.has(peer_id):
		return
	(_capsules[peer_id] as Node3D).queue_free()
	_capsules.erase(peer_id)


func _on_character_updated_capsule(peer_id: int, data: Dictionary) -> void:
	if not _capsules.has(peer_id):
		return
	(_capsules[peer_id] as Node3D).set_color(data.get("class", ""))
