extends Control
class_name SelectionManager

var draw_selection := false
var drag_start: Vector2
var select_box: Rect2
var perform_selection := false # Flag to trigger selection in _physics_process

@onready var box_color: Color = ProjectSettings.get_setting("game/interface/selection_rectangle_color", Color("#00ff0066"))
@onready var box_color_outline: Color = ProjectSettings.get_setting("game/interface/selection_rectangle_color_outline", Color("#00ff00"))
@onready var optimized_rect: bool = ProjectSettings.get_setting("game/interface/optimized_rectangle", false)
@export var rect_style: StyleBoxFlat
@onready var cam = get_viewport().get_camera_3d()


func _ready() -> void:
	if optimized_rect:return


func _unhandled_input(e: InputEvent) -> void:
	if e is InputEventMouseButton and e.button_index == MOUSE_BUTTON_LEFT:
		if e.pressed:
			draw_selection = true
			drag_start = e.position
		else:
			# When button is released
			draw_selection = false
			if drag_start.is_equal_approx(e.position):
				# Single click: set a zero-sized selection box
				select_box = Rect2(e.position, Vector2.ZERO)
				print("one click")
			else:
				# Drag: calculate the final selection box
				var x_min = min(drag_start.x, e.position.x)
				var y_min = min(drag_start.y, e.position.y)
				select_box = Rect2(x_min, y_min,
							max(drag_start.x, e.position.x) - x_min,
							max(drag_start.y, e.position.y) - y_min)

			perform_selection = true # Trigger selection in _physics_process
			queue_redraw()
	elif draw_selection and e is InputEventMouseMotion:
		# Update selection box for drawing during drag
		var x_min = min(drag_start.x, e.position.x)
		var y_min = min(drag_start.y, e.position.y)
		select_box = Rect2(x_min, y_min,
					max(drag_start.x, e.position.x) - x_min,
					max(drag_start.y, e.position.y) - y_min)

		queue_redraw()


func _physics_process(_delta: float) -> void:
	if perform_selection:
		update_selected_units()
		perform_selection = false


func check_raycast(mouse_pos: Vector2, collision_mask: int = 4294967295) -> Dictionary:
	var from = cam.project_ray_origin(mouse_pos)
	var to = from + cam.project_ray_normal(mouse_pos) * 1000 # Magic number
	var query = PhysicsRayQueryParameters3D.new()
	query.from = from
	query.to = to
	query.collision_mask = collision_mask
	var space_state = cam.get_world_3d().direct_space_state
	#DebugTools.DrawLine(from,to,25.0)
	return space_state.intersect_ray(query)


func update_selected_units() -> void:
	var units_array = get_tree().get_nodes_in_group("selectable-entity")
	var raycast = {}
	# Only perform raycast if it's a single click (zero-sized select_box)
	if select_box.size == Vector2.ZERO:
		raycast = check_raycast(select_box.position)
		if raycast:
			print("found ",raycast.collider.name)
			#breakpoint

	for entity: Entity in units_array:
		# TODO: Optimize by searching only in spawned chunks
		if select_box.size == Vector2.ZERO:
			# Single click: select entity under mouse via raycast
			if raycast and entity.is_under_mouse(raycast):
				entity.select()
			else:
				entity.deselect()
		else:
			# Drag: select entities within the selection box
			if entity.is_in_selection(select_box, cam):
				entity.select()
			else:
				entity.deselect()


func _draw() -> void:
	if not (draw_selection or perform_selection):return
	if select_box and rect_style:
		if optimized_rect:
			draw_rect(select_box,box_color)
			draw_rect(select_box,box_color_outline,false,2.0,true)
		elif rect_style:
			draw_style_box(rect_style,select_box)
