extends Node3D

## NEO-24 UX: combat dummy anchors (`prototype_target_alpha`, `prototype_target_beta`) need
## obvious world markers — a capsule body, lock ring, and [Label3D] name per
## `PrototypeTargetConstants.ANCHORS`. NEO-85: highlight the server-locked dummy via
## [method set_locked_target].
##
## Display-only; no game logic hangs off these nodes. If the server registry moves,
## update `prototype_target_constants.gd` — markers respawn on next scene load.

const PrototypeTargetConstants := preload("res://scripts/prototype_target_constants.gd")

## Visual tuning — readable from the default isometric camera at spawn.
const _DUMMY_CAPSULE_HEIGHT: float = 1.75
const _DUMMY_CAPSULE_RADIUS: float = 0.38
const _RING_RADIUS_SEGMENTS: int = 72
const _RING_Y: float = 0.05
const _RING_THICKNESS: float = 0.08
const _LABEL_Y: float = 2.15

var _markers_by_id: Dictionary = {}
var _locked_target_id: String = ""


func _ready() -> void:
	for id_variant: Variant in PrototypeTargetConstants.ANCHORS.keys():
		if not id_variant is String:
			continue
		_spawn_marker(id_variant as String)


func set_locked_target(target_id: String) -> void:
	_locked_target_id = target_id.strip_edges()
	_apply_highlight_states()


func _spawn_marker(target_id: String) -> void:
	var anchor: Vector3 = PrototypeTargetConstants.anchor_position(target_id)
	var radius: float = PrototypeTargetConstants.anchor_radius(target_id)
	var tint: Color = PrototypeTargetConstants.anchor_color(target_id)
	if radius <= 0.0:
		return

	var group := Node3D.new()
	group.name = "Marker_%s" % target_id
	group.position = anchor
	add_child(group)

	var body := MeshInstance3D.new()
	body.name = "DummyBody"
	var capsule := CapsuleMesh.new()
	capsule.radius = _DUMMY_CAPSULE_RADIUS
	capsule.height = _DUMMY_CAPSULE_HEIGHT
	body.mesh = capsule
	body.position = Vector3(0.0, _DUMMY_CAPSULE_HEIGHT * 0.5, 0.0)
	var body_mat := _make_unshaded_material(tint, 0.88)
	body.material_override = body_mat
	group.add_child(body)

	var ring: MeshInstance3D = _make_radius_ring(radius, tint)
	ring.name = "RadiusRing"
	ring.position = Vector3(0.0, _RING_Y - anchor.y, 0.0)
	group.add_child(ring)

	var label := Label3D.new()
	label.name = "NameLabel"
	label.text = PrototypeTargetConstants.display_short_name(target_id)
	label.font_size = 24
	label.outline_size = 6
	label.modulate = tint.lightened(0.15)
	label.billboard = BaseMaterial3D.BILLBOARD_ENABLED
	label.position = Vector3(0.0, _LABEL_Y, 0.0)
	group.add_child(label)

	_markers_by_id[target_id] = {
		"body_mat": body_mat,
		"ring_mat": ring.material_override,
		"tint": tint,
	}


func _apply_highlight_states() -> void:
	for id_variant: Variant in _markers_by_id.keys():
		if not id_variant is String:
			continue
		var target_id: String = id_variant as String
		var entry: Dictionary = _markers_by_id[target_id]
		var tint: Color = entry["tint"]
		var body_mat: StandardMaterial3D = entry["body_mat"]
		var ring_mat: StandardMaterial3D = entry["ring_mat"]
		var highlighted: bool = target_id == _locked_target_id and not _locked_target_id.is_empty()
		if highlighted:
			body_mat.albedo_color = tint.lightened(0.25)
			var ring_c := tint
			ring_c.a = 0.78
			ring_mat.albedo_color = ring_c
		else:
			body_mat.albedo_color = Color(tint.r, tint.g, tint.b, 0.88)
			var ring_c2 := tint
			ring_c2.a = 0.45
			ring_mat.albedo_color = ring_c2


func _make_unshaded_material(tint: Color, alpha: float) -> StandardMaterial3D:
	var m := StandardMaterial3D.new()
	m.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
	var c := tint
	c.a = alpha
	m.albedo_color = c
	if alpha < 0.999:
		m.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA
	return m


func _make_radius_ring(radius: float, tint: Color) -> MeshInstance3D:
	var mi := MeshInstance3D.new()
	var arr_mesh := ArrayMesh.new()
	var verts := PackedVector3Array()
	var normals := PackedVector3Array()
	var indices := PackedInt32Array()

	var inner: float = max(0.01, radius - _RING_THICKNESS * 0.5)
	var outer: float = radius + _RING_THICKNESS * 0.5
	var up := Vector3.UP
	for i in range(_RING_RADIUS_SEGMENTS):
		var a: float = TAU * float(i) / float(_RING_RADIUS_SEGMENTS)
		var c: float = cos(a)
		var s: float = sin(a)
		verts.append(Vector3(inner * c, 0.0, inner * s))
		verts.append(Vector3(outer * c, 0.0, outer * s))
		normals.append(up)
		normals.append(up)

	for i in range(_RING_RADIUS_SEGMENTS):
		var i_next: int = (i + 1) % _RING_RADIUS_SEGMENTS
		var a0: int = i * 2
		var a1: int = i * 2 + 1
		var b0: int = i_next * 2
		var b1: int = i_next * 2 + 1
		indices.append_array([a0, a1, b1, a0, b1, b0])

	var surface: Array = []
	surface.resize(Mesh.ARRAY_MAX)
	surface[Mesh.ARRAY_VERTEX] = verts
	surface[Mesh.ARRAY_NORMAL] = normals
	surface[Mesh.ARRAY_INDEX] = indices
	arr_mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, surface)
	mi.mesh = arr_mesh
	mi.material_override = _make_unshaded_material(tint, 0.45)
	return mi
