class_name FreeCamera extends CharacterBody3D

const SPRINT_MULT := 3.0
const PITCH_LIMIT := deg_to_rad(85.0)

@onready var _target := Vector2(rotation.x, rotation.y)

static var scene := preload("res://src/ui/camera/free_camera/free_camera.tscn")


func _unhandled_input(event: InputEvent) -> void:
	if event is InputEventMouseButton:
		Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
	elif event is InputEventMouseMotion:
		if Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED:
			camera_motion((event as InputEventMouseMotion).relative)


func camera_motion(motion: Vector2) -> void:
	_target.y = _target.y - deg_to_rad(motion.x * Game.settings.x_sensitivity)
	_target.x = clampf(
		(
			_target.x
			- (
				deg_to_rad(motion.y * Game.settings.y_sensitivity)
				* (-1 if Game.settings.invert_pitch else 1)
			)
		),
		-PITCH_LIMIT,
		PITCH_LIMIT,
	)


func _physics_process(_delta: float) -> void:
	# Rotation
	rotation.y = lerp_angle(rotation.y, _target.y, Game.settings.x_acceleration / 60.0)
	rotation.x = lerp_angle(rotation.x, _target.x, Game.settings.y_acceleration / 60.0)

	# Handle spatial movement
	var xz_input := Input.get_vector("camera_left", "camera_right", "camera_forward", "camera_back")
	var y_input := Input.get_vector("camera_down", "camera_up", "camera_down", "camera_up")
	var direction := (transform.basis * Vector3(xz_input.x, y_input.y, xz_input.y)).normalized()

	var speed := Game.settings.free_camera_speed
	if Input.is_action_pressed("camera_sprint", true):
		speed *= SPRINT_MULT

	if direction:
		velocity = direction * speed
	else:
		velocity = velocity.move_toward(Vector3.ZERO, speed)

	move_and_slide()


static func create(snap_point: Node3D) -> FreeCamera:
	var instance: FreeCamera = FreeCamera.scene.instantiate()
	instance.global_transform = snap_point.global_transform
	return instance
