extends Object

## NEO-73: client-side nearest [code]resource_node[/code] picker for gather interact ([kbd]R[/kbd]).
## Horizontal X/Z distance + inclusive radius — same rule as
## [code]interaction_radius_indicators.gd[/code].

const KIND_RESOURCE_NODE := "resource_node"
const FALLBACK_RESOURCE_NODE_ID := "prototype_resource_node_alpha"

const KNOWN_RESOURCE_NODE_IDS: Array[String] = [
	"prototype_resource_node_alpha",
	"prototype_subsurface_vein_beta",
	"prototype_bio_mat_gamma",
	"prototype_urban_bulk_delta",
]


static func nearest_resource_node_id(descriptors: Array, world: Vector3) -> String:
	var best_id := ""
	var best_dist_sq: float = INF
	for descriptor_variant in descriptors:
		if not descriptor_variant is Dictionary:
			continue
		var descriptor: Dictionary = descriptor_variant
		if str(descriptor.get("kind", "")) != KIND_RESOURCE_NODE:
			continue
		var interactable_id: String = str(descriptor.get("interactableId", ""))
		if interactable_id.is_empty():
			continue
		var dist_sq: float = _horizontal_distance_sq_to_descriptor(descriptor, world)
		var radius: float = float(descriptor.get("interactionRadius", 0.0))
		if dist_sq > radius * radius:
			continue
		if (
			best_id.is_empty()
			or dist_sq < best_dist_sq - 1e-9
			or (absf(dist_sq - best_dist_sq) <= 1e-9 and interactable_id < best_id)
		):
			best_dist_sq = dist_sq
			best_id = interactable_id
	if best_id.is_empty():
		return FALLBACK_RESOURCE_NODE_ID
	return best_id


static func descriptor_kind(descriptors: Array, interactable_id: String) -> String:
	for descriptor_variant in descriptors:
		if not descriptor_variant is Dictionary:
			continue
		var descriptor: Dictionary = descriptor_variant
		if str(descriptor.get("interactableId", "")) == interactable_id:
			return str(descriptor.get("kind", ""))
	return ""


static func is_resource_node_id(descriptors: Array, interactable_id: String) -> bool:
	if descriptor_kind(descriptors, interactable_id) == KIND_RESOURCE_NODE:
		return true
	return KNOWN_RESOURCE_NODE_IDS.has(interactable_id)


static func _horizontal_distance_sq_to_descriptor(descriptor: Dictionary, world: Vector3) -> float:
	var anchor_variant: Variant = descriptor.get("anchor", null)
	if not anchor_variant is Dictionary:
		return INF
	var anchor: Dictionary = anchor_variant
	var dx: float = world.x - float(anchor.get("x", 0.0))
	var dz: float = world.z - float(anchor.get("z", 0.0))
	return dx * dx + dz * dz
