extends Node

const TARGET_RANGE := 100.0

var mouse_press_pos: Vector2 = Vector2.ZERO

@onready var player: CharacterBody3D = get_parent()
@onready var camera: Camera3D = get_parent().get_node("CameraPivot/Camera3D")

func _unhandled_input(event: InputEvent) -> void:
  if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT:
    if event.pressed:
      mouse_press_pos = event.position
    else:
      var drag: float = event.position.distance_to(mouse_press_pos)
      if drag < 5.0:
        _try_target_under_mouse(event.position)
  if event.is_action_pressed("target_next"):
    _cycle_target()

func _try_target_under_mouse(mouse_pos: Vector2) -> void:
  var from := camera.project_ray_origin(mouse_pos)
  var to := from + camera.project_ray_normal(mouse_pos) * TARGET_RANGE
  var space := player.get_world_3d().direct_space_state
  var query := PhysicsRayQueryParameters3D.create(from, to)
  query.collision_mask = 4
  query.collide_with_areas = true
  query.collide_with_bodies = false
  var result := space.intersect_ray(query)
  if result:
    var hit_target := result.collider.get_parent() as Node3D
    if hit_target and hit_target.is_in_group("tavern"):
      EventBus.target_requested.emit(player, null)
      return
    if hit_target and (hit_target.is_in_group("enemies") or hit_target.is_in_group("portals")):
      EventBus.target_requested.emit(player, hit_target)
      return
  EventBus.target_requested.emit(player, null)

func _cycle_target() -> void:
  var enemies := get_tree().get_nodes_in_group("enemies")
  var portals := get_tree().get_nodes_in_group("portals")
  var targets: Array = []
  for e in enemies:
    if is_instance_valid(e):
      targets.append(e)
  for p in portals:
    if is_instance_valid(p):
      targets.append(p)
  if targets.is_empty():
    EventBus.target_requested.emit(player, null)
    return
  targets.sort_custom(func(a, b): return player.global_position.distance_squared_to(a.global_position) < player.global_position.distance_squared_to(b.global_position))
  var current: Node3D = PlayerData.target
  if current == null or current not in targets:
    EventBus.target_requested.emit(player, targets[0])
    return
  var idx := targets.find(current)
  var next_idx := (idx + 1) % targets.size()
  EventBus.target_requested.emit(player, targets[next_idx])
