class_name PlayerController extends CharacterBody3D

signal hit_static_body(rid, position)

@export var debug: bool = false
@export_category("References")
@export var camera: CameraController
@export var camera_effects: CameraEffects
@export var state_chart: StateChart
@export var standing_collision: CollisionShape3D
@export var crouching_collision: CollisionShape3D
@export var crouch_check: ShapeCast3D
@export var interaction_raycast: RayCast3D
@export var step_handler: StepHandlerComponet
@export_category("Movement Settings")
@export_group("Easing")
@export var acceleration: float = 0.2
@export var deceleration: float = 0.5
@export_group("Speed")
@export var default_speed: float = 7.0
@export var sprint_speed: float = 3.0
@export var crouch_speed: float = -5.0
@export_category("Jump Settings")
@export var jump_velocity: float = 5.0
@export var fall_velocity_threashold: float = -5.0

var _input_dir: Vector2 = Vector2.ZERO
var _movement_velocity: Vector3 = Vector3.ZERO
var sprint_modifier: float = 0.0
var crouch_modifier: float = 0.0
var speed: float = 0.0
var current_fall_velocity: float
var previous_velocity: Vector3

func _input(event: InputEvent) -> void:
	if event.is_action_pressed("left_click"):
		var center = camera_effects.get_camera_center()
		var ray_orgin = camera_effects.project_ray_origin(center)
		var ray_end = ray_orgin + camera_effects.project_ray_normal(center) * 1000
		
		var new_intersection = PhysicsRayQueryParameters3D.create(ray_orgin, ray_end)
		var query = get_world_3d().direct_space_state.intersect_ray(new_intersection)
		
		if query:
			var collider = query["collider"]
			var wall = collider.get_parent().get_parent()
			if wall and wall is DestructableWall:
				wall.hit(query["position"])

func _physics_process(delta: float) -> void:
	previous_velocity = self.velocity
	
	if not is_on_floor():
		velocity += get_gravity() * delta
		
	var speed_modifier = sprint_modifier + crouch_modifier
	speed = default_speed + speed_modifier
	
	_input_dir = Input.get_vector("move_left", "move_right", "move_forward", "move_backward")
	var current_velocity = Vector2(_movement_velocity.x, _movement_velocity.z)
	var direction = (transform.basis * Vector3(_input_dir.x, 0, _input_dir.y)).normalized()
	
	if direction:
		current_velocity = lerp(current_velocity, Vector2(direction.x, direction.z) * speed, acceleration)
	else:
		current_velocity = current_velocity.move_toward(Vector2.ZERO, deceleration)
	
	_movement_velocity = Vector3(current_velocity.x, velocity.y, current_velocity.y)
	
	velocity = _movement_velocity

	move_and_slide()
	
	if is_on_floor():
		step_handler.handle_step_climbing()

func get_input_direction() -> Vector2:
	return _input_dir

func update_rotation(rotation_input) -> void:
	global_transform.basis = Basis.from_euler(rotation_input)


func sprint() -> void:
	sprint_modifier = sprint_speed

func walk() -> void:
	sprint_modifier = 0.0

func stand() -> void:
	crouch_modifier = 0.0
	standing_collision.disabled = false
	crouching_collision.disabled = true

func crouch() -> void:
	crouch_modifier = crouch_speed
	standing_collision.disabled = true
	crouching_collision.disabled = false

func jump() -> void:
	velocity.y += jump_velocity

func check_fall_speed() -> bool:
	if current_fall_velocity < fall_velocity_threashold:
		current_fall_velocity = 0.0
		return true
	
	current_fall_velocity = 0.0
	return false
