extends RigidBody3D
class_name Car

@export var road_path : SplinePath

@export var forward_force: float = 100.0
@export var backward_force: float = 50.0
@export var steer_speed: float = 2.0

@export var base_lateral_friction: float = 5.0

@onready var forward_left: RayCast3D = $ForwardLeft
@onready var forward_right: RayCast3D = $ForwardRight
@onready var backward_right: RayCast3D = $BackwardRight
@onready var backward_left: RayCast3D = $BackwardLeft

@onready var forward_left_respawn: RayCast3D = $RaycastsRespawn/ForwardLeftRespawn
@onready var forward_right_respawn: RayCast3D = $RaycastsRespawn/ForwardRightRespawn
@onready var backward_right_respawn: RayCast3D = $RaycastsRespawn/BackwardRightRespawn
@onready var backward_left_respawn: RayCast3D = $RaycastsRespawn/BackwardLeftRespawn



var base_steer_speed: float
var current_steer_speed = base_steer_speed
var last_steer_input := 0.0
var rotation_angle := 0.0

var respawn_trans : Transform3D 

var thread: Thread = Thread.new()
var steer_input = 0.0

var air_time := 0.0


func custom_gravity() -> Vector3:
	var closest_offset = road_path.curve.get_closest_offset(road_path.to_local(position))
	var closest_transform = road_path.curve.sample_baked_with_rotation(closest_offset, true, true)
	
	return -closest_transform.basis.y

func return_to_road():
	var closest_offset = road_path.curve.get_closest_offset(road_path.to_local(position))
	var closest_transform = road_path.curve.sample_baked_with_rotation(closest_offset, true, true)
	transform = respawn_trans
	position += closest_transform.basis.y * 2.0
	
	linear_velocity = Vector3.ZERO
	angular_velocity = Vector3.ZERO
	
	air_time = 0.0
	
func _process(_delta: float) -> void:
	
	if Input.is_action_just_pressed("restart"):
		return_to_road()
		
	if Input.is_action_just_pressed("hardRestart"):
		get_tree().reload_current_scene()

func _physics_process(delta: float) -> void:
	var move_input := Input.get_axis("back", "forward")
	var steer_input_brut := Input.get_axis("right", "left")
	steer_input = lerpf(steer_input, steer_input_brut, 0.1)
	var is_on_floor := backward_left_respawn.is_colliding() || backward_right_respawn.is_colliding() || forward_left_respawn.is_colliding() || forward_right_respawn.is_colliding()
	var is_all_wheel_on_floor := backward_left_respawn.is_colliding() && backward_right_respawn.is_colliding() && forward_left_respawn.is_colliding() && forward_right_respawn.is_colliding()
	
	# Doing custom gravity like a chad
	PhysicsServer3D.area_set_param(get_viewport().find_world_3d().space, PhysicsServer3D.AREA_PARAM_GRAVITY_VECTOR, custom_gravity())
	
	if is_all_wheel_on_floor:
		respawn_trans = transform

	if !is_on_floor:
		air_time += delta
		if air_time > 3:
			return_to_road()
		return
	air_time = 0.0
		
	# Movement
	if move_input > 0.0:
		apply_central_force(global_transform.basis.z * forward_force)
	elif move_input < 0.0:
		var break_or_backward = 2*backward_force if global_transform.basis.z.dot(linear_velocity) > 0 else backward_force
		apply_central_force(global_transform.basis.z * -break_or_backward)

	# Rotation
	rotation_angle = steer_input * delta
	rotate(global_transform.basis.y, rotation_angle)
	
	var velocity = linear_velocity
	var forward_dir = global_transform.basis.z
	if forward_dir.length_squared() == 0.0:
		return 
	forward_dir = forward_dir.normalized()

	var forward_velocity = forward_dir * velocity.dot(forward_dir)
	var lateral_velocity = velocity - forward_velocity

	var lateral_friction_force = -lateral_velocity * base_lateral_friction
	apply_central_force(lateral_friction_force)
	
	
