extends Node3D

@export var target: Node3D

@export var follow_offset := Vector3(0, 10, 8)
@export var follow_speed := 12.0
@export var rotation_smooth_speed := 18.0
@export var focus_smooth_speed := 14.0

@export var mouse_sensitivity := 0.002

@export var deadzone_right := 3.0
@export var deadzone_forward := 3.0

var yaw := 0.0
var smoothed_yaw := 0.0

var focus_position := Vector3.ZERO
var desired_focus_position := Vector3.ZERO


func _ready() -> void:
	Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)

	if target:
		focus_position = target.global_position
		desired_focus_position = focus_position
		global_position = focus_position + follow_offset


func _unhandled_input(event: InputEvent) -> void:
	if event is InputEventMouseMotion:
		yaw -= event.relative.x * mouse_sensitivity

	if event.is_action_pressed("ui_cancel"):
		Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)


func _physics_process(delta: float) -> void:
	if target == null:
		return

	var rot_t := 1.0 - exp(-rotation_smooth_speed * delta)
	var focus_t := 1.0 - exp(-focus_smooth_speed * delta)
	var follow_t := 1.0 - exp(-follow_speed * delta)

	smoothed_yaw = lerp_angle(smoothed_yaw, yaw, rot_t)

	rotation = Vector3(deg_to_rad(-55), smoothed_yaw, 0)

	var target_pos := target.global_position
	var diff := target_pos - desired_focus_position

	var cam_right := Vector3.RIGHT.rotated(Vector3.UP, smoothed_yaw).normalized()
	var cam_forward := Vector3.FORWARD.rotated(Vector3.UP, smoothed_yaw).normalized()

	var diff_right := diff.dot(cam_right)
	var diff_forward := diff.dot(cam_forward)

	if abs(diff_right) > deadzone_right:
		desired_focus_position += cam_right * (diff_right - sign(diff_right) * deadzone_right)

	if abs(diff_forward) > deadzone_forward:
		desired_focus_position += (
			cam_forward * (diff_forward - sign(diff_forward) * deadzone_forward)
		)

	focus_position = focus_position.lerp(desired_focus_position, focus_t)

	var rotated_offset := follow_offset.rotated(Vector3.UP, smoothed_yaw)
	var desired_position := focus_position + rotated_offset

	global_position = global_position.lerp(desired_position, follow_t)
