extends Node

const TAVERN_SCENE := "res://scenes/tavern.tscn"
const FLOOR_THRESHOLD := 3.5  # y < threshold → EG, y >= threshold → OG
const OVERLAY_CYCLE := ["default", "spore_active"]

var _dm_roll_log: RichTextLabel

var _eg_markers: Node3D
var _og_markers: Node3D
var _eg_markers_by_id: Dictionary = {}  # peer_id → MeshInstance3D
var _og_markers_by_id: Dictionary = {}  # peer_id → MeshInstance3D
var _player_cam_cams: Dictionary = {}   # peer_id → Camera3D (in SubViewport)


func _ready() -> void:
	$RootLayout.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
	_load_tavern_into_viewports()
	_setup_player_cams()
	_setup_overlay_panel()
	_setup_dc_section()


func _load_tavern_into_viewports() -> void:
	var packed := ResourceLoader.load(TAVERN_SCENE, "PackedScene") as PackedScene
	if packed == null:
		push_error("[DmView] tavern.tscn nicht gefunden")
		return

	var eg_root := $RootLayout/TopSection/MapsAndSide/EGContainer/EGViewport/EGRoot as Node3D
	_eg_markers = eg_root.get_node("EGMarkers") as Node3D
	eg_root.add_child(packed.instantiate())

	var og_root := $RootLayout/TopSection/MapsAndSide/OGContainer/OGViewport/OGRoot as Node3D
	_og_markers = og_root.get_node("OGMarkers") as Node3D
	og_root.add_child(packed.instantiate())

	print("[DmView] Tavern in EG- und OG-Viewport geladen")


# --- Player Cam Feeds ---

func _setup_player_cams() -> void:
	NetworkManager.player_joined.connect(_on_player_joined_cam)
	NetworkManager.player_left.connect(_on_player_left_cam)
	for peer_id in NetworkManager.players.keys():
		var info: Dictionary = NetworkManager.players[peer_id]
		if info.get("role", "") == "player":
			_create_player_cam(peer_id, info.get("name", "???"))


func _on_player_joined_cam(peer_id: int, player_name: String, role: String) -> void:
	if role == "player":
		_create_player_cam(peer_id, player_name)


func _on_player_left_cam(peer_id: int) -> void:
	var panel := $RootLayout/PlayerCamsRow.get_node_or_null("CamPanel_%d" % peer_id)
	if panel != null:
		panel.queue_free()
	_player_cam_cams.erase(peer_id)
	_eg_markers_by_id.erase(peer_id)
	_og_markers_by_id.erase(peer_id)


func _create_player_cam(peer_id: int, player_name: String) -> void:
	var packed := ResourceLoader.load(TAVERN_SCENE, "PackedScene") as PackedScene
	if packed == null:
		push_error("[DmView] tavern.tscn nicht gefunden für Player-Cam")
		return

	var viewport := SubViewport.new()
	viewport.size = Vector2i(320, 180)

	var scene_root := Node3D.new()
	scene_root.add_child(packed.instantiate())

	var cam := Camera3D.new()
	cam.name = "PlayerCam"
	cam.current = true
	scene_root.add_child(cam)
	viewport.add_child(scene_root)

	var container := SubViewportContainer.new()
	container.name = "CamPanel_%d" % peer_id
	container.custom_minimum_size = Vector2(320, 180)
	container.stretch = true
	container.add_child(viewport)

	var wrapper := VBoxContainer.new()
	var label := Label.new()
	label.text = player_name
	label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
	wrapper.add_child(label)
	wrapper.add_child(container)

	$RootLayout/PlayerCamsRow.add_child(wrapper)
	_player_cam_cams[peer_id] = cam
	print("[DmView] Player-Cam erstellt für %s (Peer %d)" % [player_name, peer_id])


# --- Overlay Panel ---

func _setup_overlay_panel() -> void:
	NetworkManager.player_joined.connect(_on_player_joined)
	NetworkManager.player_left.connect(_on_player_left)
	for peer_id in NetworkManager.players.keys():
		var info: Dictionary = NetworkManager.players[peer_id]
		if info.get("role", "") == "player":
			_add_overlay_row(peer_id, info.get("name", "???"))


func _on_player_joined(peer_id: int, player_name: String, role: String) -> void:
	if role == "player":
		_add_overlay_row(peer_id, player_name)


func _on_player_left(peer_id: int) -> void:
	var list := $RootLayout/TopSection/SidePanel/OverlayScroll/PlayerList as VBoxContainer
	var row := list.get_node_or_null("Row_%d" % peer_id)
	if row != null:
		row.queue_free()


func _add_overlay_row(peer_id: int, player_name: String) -> void:
	var list := $RootLayout/TopSection/SidePanel/OverlayScroll/PlayerList as VBoxContainer
	var row := HBoxContainer.new()
	row.name = "Row_%d" % peer_id
	var label := Label.new()
	label.text = player_name
	label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
	var btn := Button.new()
	btn.text = "● default"
	btn.pressed.connect(func() -> void: _toggle_overlay(peer_id, btn))
	row.add_child(label)
	row.add_child(btn)
	list.add_child(row)


func _toggle_overlay(peer_id: int, btn: Button) -> void:
	var current := GameState.get_overlay(peer_id)
	var idx := OVERLAY_CYCLE.find(current)
	var next: String = OVERLAY_CYCLE[(idx + 1) % OVERLAY_CYCLE.size()]
	NetworkManager.request_set_overlay.rpc_id(1, peer_id, next)
	GameState.set_overlay_local(peer_id, next)
	btn.text = "● %s" % next
	print("[DmView] Overlay-Toggle → Spieler %d: %s" % [peer_id, next])


# --- _process: Marker + Cam updates ---

func _process(_delta: float) -> void:
	_update_player_markers()
	_update_player_cams()


func _update_player_markers() -> void:
	if _eg_markers == null or _og_markers == null:
		return
	for peer_id in GameState.player_positions.keys():
		var data: Dictionary = GameState.player_positions[peer_id]
		var pos: Vector3 = data.get("position", Vector3.ZERO)
		var rot: Vector3 = data.get("rotation", Vector3.ZERO)
		var is_upper := pos.y >= FLOOR_THRESHOLD

		var eg_marker := _get_or_create_marker(peer_id, _eg_markers, _eg_markers_by_id)
		eg_marker.global_position = pos + Vector3(0, 0.2, 0)
		eg_marker.rotation.y = rot.y
		eg_marker.visible = not is_upper

		var og_marker := _get_or_create_marker(peer_id, _og_markers, _og_markers_by_id)
		og_marker.global_position = pos + Vector3(0, 0.2, 0)
		og_marker.rotation.y = rot.y
		og_marker.visible = is_upper


func _get_or_create_marker(peer_id: int, parent: Node3D, registry: Dictionary) -> MeshInstance3D:
	if peer_id in registry:
		return registry[peer_id]
	var mesh := MeshInstance3D.new()
	var sphere := SphereMesh.new()
	sphere.radius = 0.25
	sphere.height = 0.5
	mesh.mesh = sphere
	var mat := StandardMaterial3D.new()
	mat.albedo_color = _peer_color(peer_id)
	mat.emission_enabled = true
	mat.emission = mat.albedo_color
	mat.emission_energy_multiplier = 0.5
	mesh.material_override = mat
	parent.add_child(mesh)
	registry[peer_id] = mesh
	print("[DmView] Marker erstellt für Peer %d" % peer_id)
	return mesh


func _peer_color(peer_id: int) -> Color:
	var colors := [Color.RED, Color.CYAN, Color.YELLOW, Color.MAGENTA, Color.GREEN]
	return colors[peer_id % colors.size()]


func _setup_dc_section() -> void:
	_dm_roll_log = $RootLayout/TopSection/SidePanel/RollLogScroll/RollLog as RichTextLabel
	NetworkManager.roll_received.connect(_on_roll_received_dm)


func _on_roll_received_dm(roller_peer_id: int, player_name: String, d20_result: int, modifier: int, total: int) -> void:
	var dc: int = ($RootLayout/TopSection/SidePanel/DCRow/DCSpinBox as SpinBox).value as int
	var mod_str := " %+d" % modifier if modifier != 0 else ""
	var success := total >= dc
	var result_str := "[color=green]Erfolg[/color]" if success else "[color=red]Fehlschlag[/color]"
	var line := "[b]%s[/b]: %d%s = [b]%d[/b] vs DC%d → %s" % [player_name, d20_result, mod_str, total, dc, result_str]
	if d20_result == 20:
		line += " [color=gold]★[/color]"
	elif d20_result == 1:
		line += " [color=red]☠[/color]"
	_dm_roll_log.append_text(line + "\n")


func _update_player_cams() -> void:
	for peer_id in _player_cam_cams.keys():
		if not GameState.player_positions.has(peer_id):
			continue
		var data: Dictionary = GameState.player_positions[peer_id]
		var pos: Vector3 = data.get("position", Vector3.ZERO)
		var rot: Vector3 = data.get("rotation", Vector3.ZERO)
		var cam: Camera3D = _player_cam_cams[peer_id]
		cam.global_position = pos
		cam.global_rotation = rot
