extends Camera3D
class_name TrainControlCamera

@export var train: Node3D
enum CameraMode { FOLLOW, SIDE, TOP, COCKPIT, CINEMATIC }

@export_group("Camera")
@export var follow_distance: float = 18.0
@export var follow_height: float = 7.0
@export var smoothness: float = 4.0

var mode: CameraMode = CameraMode.FOLLOW
var orbit_angle: float = 0.0
var cinematic_angle: float = 0.0


func _process(delta):
	_handle_input(delta)
	
	match mode:
		CameraMode.FOLLOW:
			_update_follow(delta)
		CameraMode.SIDE:
			_update_side(delta)
		CameraMode.TOP:
			_update_top(delta)
		CameraMode.COCKPIT:
			_update_cockpit(delta)
		CameraMode.CINEMATIC:
			_update_cinematic(delta)
			
				
func _handle_input(delta: float) -> void:
	if Input.is_action_just_pressed("ui_accept"):
		mode = ((mode + 1) % CameraMode.size()) as CameraMode
		orbit_angle = 0.0
	
	if Input.is_action_pressed("camera_left"):
		orbit_angle -= 2.0 * delta
	elif Input.is_action_pressed("camera_right"):
		orbit_angle += 2.0 * delta
	
	orbit_angle = clamp(orbit_angle, -PI/2.5, PI/2.5)


func _update_follow(delta: float) -> void:
	if not train:
		return
	
	var train_pos = train.global_position
	var forward = -train.global_transform.basis.z
	var right = train.global_transform.basis.x
	
	var rotated = forward * cos(orbit_angle) + right * sin(orbit_angle)
	var target_pos = train_pos - rotated * follow_distance + Vector3.UP * follow_height
	var target_look = train_pos + Vector3.UP * 2.0
	
	global_position = global_position.lerp(target_pos, smoothness * delta)
	look_at(target_look, Vector3.UP)


func _update_side(delta: float) -> void:
	if not train:
		return

	var train_pos = train.global_position
	var right = train.global_transform.basis.x
	
	var side_dir = sign(orbit_angle) if abs(orbit_angle) > 0.1 else 1.0
	var target_pos = train_pos + right * 12.0 * side_dir + Vector3.UP * 4.0
	
	global_position = global_position.lerp(target_pos, smoothness * delta)
	look_at(train_pos + Vector3.UP * 1.5, Vector3.UP)


func _update_top(delta: float) -> void:
	if not train:
		return

	var train_pos = train.global_position
	var target_pos = train_pos + Vector3.UP * 35.0
	
	global_position = global_position.lerp(target_pos, smoothness * delta)
	look_at(train_pos, Vector3.FORWARD)


func _update_cockpit(delta: float) -> void:
	if not train:
		return

	# Offset: dentro la cabina
	var cockpit_pos = train.global_position + train.global_transform.basis * Vector3(0, 3.2, 1.5)
	var forward_point = train.global_position - (-train.global_transform.basis.z) * 40.0
	
	var look_offset = train.global_transform.basis.x * orbit_angle * 15.0
	
	global_position = global_position.lerp(cockpit_pos, smoothness * 2.0 * delta)
	look_at(forward_point + look_offset + Vector3.UP * 1.0, Vector3.UP)


func _update_cinematic(delta: float) -> void:
	if not train:
		return

	var train_pos = train.global_position
	
	cinematic_angle += 0.25 * delta
	
	var offset = Vector3(
		cos(cinematic_angle) * 22.0,
		8.0 + sin(cinematic_angle * 0.5) * 4.0,
		sin(cinematic_angle) * 22.0
	)
	
	var target_pos = train_pos + offset
	global_position = global_position.lerp(target_pos, smoothness * 0.4 * delta)
	look_at(train_pos + Vector3.UP * 1.5, Vector3.UP)


func get_mode_name() -> String:
	match mode:
		CameraMode.FOLLOW: return "Segue"
		CameraMode.SIDE: return "Laterale"
		CameraMode.TOP: return "Alto"
		CameraMode.COCKPIT: return "Prima persona"
		CameraMode.CINEMATIC: return "Cinematica"
	return "Sconosciuta"
