class_name MechCharacter
extends DamageableBody

enum Equipment {
	AUTOCANNON,
	RIFLE,
}

const BASE_SPEED: float = 3.4
const BOOST_FORCE: float = 20.0
const JUMP_FORCE: float = 12.0
const TURN_SENSITIVITY: float = 0.02
const MOVEMENT_SENSITIVITY: float = 0.7

@export var _equipment: Equipment = Equipment.AUTOCANNON

var _weapon: Weapon = null
var _boost_triggered: bool = false

@onready var autocannon: Weapon = %WeaponSlot/Autocannon
@onready var rifle: Weapon = %WeaponSlot/Rifle

@onready var mesh: Node3D = $Mesh
@onready var animation_tree: AnimationTree = $Mesh/Mech/AnimationTree
@onready var shadow_listener: ShadowListener = $ShadowListener
@onready var spark_shower: GPUParticles3D = $SparkShower
@onready var boost_cooldown_timer: Timer = $BoostCooldownTimer


func shutdown() -> void:
	animation_tree["parameters/online_state/transition_request"] = "offline"
	spark_shower.emitting = true


func is_boosting() -> bool:
	return _boost_triggered or animation_tree["parameters/boost/active"]


func in_shadow() -> bool:
	return shadow_listener.in_shadow()


func boost_ready() -> bool:
	return boost_cooldown_timer.is_stopped()


func boost(movement: Vector3) -> void:
	velocity.x += movement.x * BOOST_FORCE
	velocity.z += movement.z * BOOST_FORCE
	velocity.y = 0.0
	mesh.rotation.y = atan2(velocity.x, velocity.z)
	animation_tree["parameters/boost/request"] = 1
	_boost_triggered = true
	boost_cooldown_timer.start()


func jump() -> void:
	if is_on_floor():
		velocity.y = JUMP_FORCE
		if is_boosting():
			# Jump cancels boost
			animation_tree["parameters/boost/request"] = 2  # Abort


func _ready() -> void:
	set_equipment(_equipment)


func set_equipment(value: Equipment) -> void:
	if _weapon:
		_weapon.deactivate()
		_weapon.visible = false
		_weapon = null

	match value:
		Equipment.AUTOCANNON:
			_weapon = autocannon
			_weapon.visible = true
		Equipment.RIFLE:
			_weapon = rifle
			_weapon.visible = true


func physics_process(movement: Vector3, delta: float) -> void:
	var delta_factor: float = delta * GameState.TARGET_FPS
	var effective_gravity: float = GameState.gravity

	if is_boosting():
		effective_gravity *= 0.1

	# Add the gravity.
	if not is_on_floor():
		velocity.y -= effective_gravity * delta
		animation_tree["parameters/jump_state/transition_request"] = "in_air"
		animation_tree["parameters/anim_state/transition_request"] = "air"
	elif animation_tree["parameters/anim_state/current_state"] == "air":
		# If not on floor but still in jump state, transition back to landing
		animation_tree["parameters/jump_state/transition_request"] = "end"

	if movement:
		if not is_boosting():
			velocity.x = lerpf(
				velocity.x, movement.x * BASE_SPEED, delta_factor * MOVEMENT_SENSITIVITY
			)
			velocity.z = lerpf(
				velocity.z, movement.z * BASE_SPEED, delta_factor * MOVEMENT_SENSITIVITY
			)

	var drag: float = (
		GameState.FRICTION if (is_on_floor() and not is_boosting()) else GameState.AIR_DRAG
	)
	velocity.x = lerpf(velocity.x, 0.0, delta_factor * drag)
	velocity.z = lerpf(velocity.z, 0.0, delta_factor * drag)

	move_and_slide()

	_boost_triggered = false
