## SnapReceiver — scans for nearby SnapPoints when the parent Character is released.
## Attach as child of Character. Connects automatically to DragDropComponent signals.
class_name SnapReceiver extends Node

const SCAN_RADIUS: float = 80.0

var _current_snap: SnapPoint = null
var _character: Character


func _ready() -> void:
	_character = get_parent() as Character
	var drag: DragDropComponent = _character.get_node_or_null("DragDropComponent") as DragDropComponent
	if drag != null:
		drag.drag_picked_up.connect(_on_drag_picked_up)
		drag.drag_released.connect(_on_drag_released)


func _on_drag_picked_up(_pos: Vector2) -> void:
	if _current_snap != null:
		_current_snap.unsnap()
		_current_snap = null
	_character.set_animation_state("held")


func _on_drag_released(_pos: Vector2) -> void:
	var nearest: SnapPoint = _find_nearest_accepting_snap()
	if nearest != null:
		_current_snap = nearest
		nearest.snap(_character)
		_character.global_position = nearest.global_position
		_character.set_animation_state(nearest.pose)
	else:
		_character.set_animation_state("idle")


func _find_nearest_accepting_snap() -> SnapPoint:
	var best: SnapPoint = null
	var best_dist: float = SCAN_RADIUS
	for node: Node in get_tree().get_nodes_in_group("snap_points"):
		var snap_point: SnapPoint = node as SnapPoint
		if snap_point == null:
			continue
		if not snap_point.accepts(_character):
			continue
		var dist: float = _character.global_position.distance_to(snap_point.global_position)
		if dist < best_dist:
			best_dist = dist
			best = snap_point
	return best


func get_current_snap() -> SnapPoint:
	return _current_snap


func force_unsnap() -> void:
	if _current_snap == null:
		return
	_current_snap.unsnap()
	_current_snap = null
	_character.set_animation_state("idle")
