class_name MovementComponent
extends CharacterComponent

static var ticks_per_second := ProjectSettings.get_setting("physics/common/physics_ticks_per_second") as float
static var gravity := ProjectSettings.get_setting("physics/3d/default_gravity") as float

@export var body: CharacterBody3D
@export var move_speed := 4.5
@export var jump_velocity := 4.5
@export var deceleration_speed := 20

var direction: Vector3
var physics_position: Vector3

func _ready():
	physics_position = character.position
	character.controlled.connect(on_controlled)

func _process(delta: float):
	if (physics_position - character.position).length_squared() < 0.00001:
		return
	
	character.position = Math.damp_vector(character.position, physics_position, ticks_per_second * delta)

func _physics_process(delta: float):
	begin_physics()
	move(delta)
	end_physics()

func move(delta: float):
	if direction:
		body.velocity.x = direction.x * move_speed
		body.velocity.z = direction.z * move_speed
	else:
		body.velocity.x = Math.dampf(body.velocity.x, 0, deceleration_speed * delta)
		body.velocity.z = Math.dampf(body.velocity.z, 0, deceleration_speed * delta)

	if !body.is_on_floor():
		body.velocity.y -= gravity * delta

	if !body.velocity:
		return
	
	body.move_and_slide()

func begin_physics():
	body.global_position = physics_position

func end_physics():
	physics_position = body.global_position
	body.position = Vector3.ZERO

func can_jump() -> bool:
	return body.is_on_floor()

func jump():
	body.velocity.y = jump_velocity

func on_controlled(controller: Controller):
	controller.direction_changed.connect(on_direction_changed)
	controller.jumped.connect(jump)

func on_direction_changed(new_direction: Vector3):
	direction = new_direction