class_name Character3D
extends StairsCharacter3D

@export var movement: CharacterMovement
@export var speed_scale: float = 1.0

var speed: float = 0.0
var movement_direction: Vector3
var ground_control: float = 1.0
var air_control: float = 1.0
# If [code]true[/code], [member air_control] won't be reset to [code]1.0[/code] when touching the ground.
var freeze_air_control: bool = false
var last_platform_velocity := Vector3.ZERO
var _was_on_floor: bool = false
var previous_velocity: Vector3


func move(direction: Vector3, delta: float) -> void:
	direction *= speed * speed_scale

	var on_floor: bool = is_on_floor()

	if on_floor:
		last_platform_velocity = get_platform_velocity()

		# Remove platform velocity when landing.
		if not _was_on_floor:
			velocity -= get_platform_velocity() # TODO: Test if last_platform_velocity is desired.
	else:
		direction += last_platform_velocity

	_was_on_floor = on_floor

	var acceleration: float = movement.max_acceleration if on_floor else movement.max_air_acceleration
	var deceleration: float = movement.max_friction if on_floor else movement.max_air_friction
	var turning_speed: float = movement.max_turning_speed if on_floor else movement.max_air_turning_speed

	var speed_change: float = acceleration

	if direction.is_zero_approx():
		speed_change = deceleration
	else:
		var flat_velocity: Vector3 = velocity * Utils.VEC3_HOR

		if direction.sign() != flat_velocity.sign():
			speed_change = turning_speed

	#DebugDraw3D.draw_arrow(global_position, global_position + direction, Color.ORANGE, 0.5, true)
	direction.y = velocity.y

	speed_change *= ground_control if on_floor else air_control

	if on_floor and not freeze_air_control:
		air_control = 1.0

	velocity = velocity.move_toward(direction, speed_change * delta)

	await get_tree().physics_frame
	previous_velocity = velocity
	#DebugDraw3D.draw_arrow(global_position, global_position + velocity, Color.BLUE, 0.5, true)
	#SPrint.print_msg("%s Velocity: %s" % [self , velocity], 0.02)


## @tutorial: https://gmtk.itch.io/platformer-toolkit/devlog/395523/behind-the-code
func apply_gravity(delta: float) -> void:
	var margin: float = movement.gravity_check_margin
	var gravity_multiplier: float = 1.0

	if velocity.y < -margin:
		#SPrint.print_msg("Falling\n%s" % velocity.y, 0.02)
		gravity_multiplier = movement.fall_gravity_multiplier
	elif velocity.y > margin:
		#SPrint.print_msg("Rising\n%s" % velocity.y, 0.02)
		gravity_multiplier = movement.rise_gravity_multiplier
	else:
		#SPrint.print_msg("Peaking\n%s" % velocity.y, 0.02)
		gravity_multiplier = movement.peak_gravity_multiplier

	velocity.y -= (movement.get_gravity() * gravity_multiplier) * delta


## @tutorial: https://gmtk.itch.io/platformer-toolkit/devlog/395523/behind-the-code
func jump() -> void:
	var jump_strength: float = sqrt(-2.0 * -movement.get_gravity() * movement.jump_height)

	if velocity.y > 0.0:
		jump_strength = maxf(jump_strength - velocity.y, 0.0)
	elif velocity.y < 0.0:
		jump_strength += absf(velocity.y)

	velocity.y += jump_strength
