class_name Biplan
extends SeatedVehicle

const PLANE_FORWARD := Vector3.BACK # z increases when moving forward

@export var thrust_power: float = 3500.0
@export var turn_to_torque: float = 3000.0
@export var move_to_pitch: float = 4000.0
@export var wing_resistance: float = 2500.0
@export var foil_resistance: float = 250.0
@export var lift: float = 25.0

var target_torque: float = 0.0
var target_pitch: float = 0.0
var target_rotation := Vector3.ZERO
var target_thrust := Vector3.ZERO

@onready var VerticalFoil : Node3D = $VerticalFoil


func trigger_thrust(activate: bool) -> void:
	if activate:
		target_thrust = PLANE_FORWARD * thrust_power
	else:
		target_thrust = Vector3.ZERO


func trigger_direction(dir: Vector2) -> void:
	target_torque = dir.x * turn_to_torque
	target_pitch = dir.y * move_to_pitch


func _physics_process(_delta) -> void:
	# Command part
	_apply_plane_rotation()
	_apply_plane_thrust()

	# Air simulation part
	if is_sleeping():
		return

	_apply_wing_resistance()
	_apply_foil_resistance()
	_apply_lift()
	transform = transform.orthonormalized()


func _apply_plane_rotation() -> void:
	var torque: Vector3 = transform.basis * Vector3(target_pitch, 0.0, target_torque)
	apply_torque(torque)


func _apply_plane_thrust() -> void:
	var force: Vector3 = transform.basis * target_thrust
	apply_central_force(force)


func _apply_wing_resistance() -> void:
	var vertical_speed = linear_velocity.dot(transform.basis * Vector3.UP)
	var local_wing_force = Vector3.UP * -wing_resistance * vertical_speed
	var wing_force = transform.basis * local_wing_force
	apply_central_force(wing_force)


func _apply_foil_resistance() -> void:
	var horizontal_speed = linear_velocity.dot(transform.basis.x)
	var local_foil_force = transform.basis.x * -foil_resistance * horizontal_speed

	var foil_local_position: Vector3 = VerticalFoil.get_position()
	var foil_global_offset: Vector3 = transform.basis * foil_local_position

	apply_force(local_foil_force, foil_global_offset)


func _apply_lift() -> void:
	var forward_speed = linear_velocity.dot(transform.basis * PLANE_FORWARD)
	if forward_speed < 0.0 :
		forward_speed = 0.0
	var local_lift_force = Vector3.UP * lift * forward_speed
	var lift_force = transform.basis * local_lift_force
	apply_central_force(lift_force)


func _on_dir_changed(dir: Vector2) -> void:
	trigger_direction(dir)


func _on_main_action(pressed: bool) -> void:
	trigger_thrust(pressed)
