class_name ShotSetup extends Node3D

enum Phase {
	AIM,
	POWER_ADJUST,
	CURVE_ADJUST,
	SHOT,
	FINISHED,
}

const PITCH_MIN := deg_to_rad(-60.0)
const PITCH_MAX := deg_to_rad(-5.0)
const ZOOM_LENGTH := 0.1

const ZOOM_MIN := 1.0
const ZOOM_MAX := 12.0

const ARROW_ACCELERATION := 8.0

const FREE_CAM_RETURN_TIME := 1.0

@export var control_disabled := false

var base_speed: float = ProjectSettings.get_setting("game/config/controls/camera/free_camera_speed")

var x_sensitivity: float = ProjectSettings.get_setting(
	"game/config/controls/camera/x_axis_sensitivity"
)
var x_acceleration: float = ProjectSettings.get_setting(
	"game/config/controls/camera/x_axis_acceleration"
)
var y_sensitivity: float = ProjectSettings.get_setting(
	"game/config/controls/camera/y_axis_sensitivity"
)
var y_acceleration: float = ProjectSettings.get_setting(
	"game/config/controls/camera/y_axis_acceleration"
)

var invert_pitch: bool = ProjectSettings.get_setting("game/config/controls/camera/invert_pitch")

var phase: Phase:
	set(value):
		if value != phase:
			_on_phase_change(value)
		phase = value

var _free_camera: FreeCamera
var _returning_free_camera := false

@onready var direction: Node3D = %Direction
@onready var pitch: Node3D = %Pitch
@onready var camera: Camera3D = %Camera
@onready var arrow: Node3D = %Arrow

@onready var power_bar: ProgressBar = %PowerBar
@onready var power_animation: AnimationPlayer = %PowerAnimation

@onready var curve_bar: ProgressBar = %CurveBar
@onready var curve_animation: AnimationPlayer = %CurveAnimation

@onready var camera_distance := camera.position.z:
	set = _set_camera_distance

@onready var _target_rotation := Vector2(pitch.rotation.x, direction.rotation.y)


func _set_camera_distance(value: float) -> void:
	var tween := get_tree().create_tween()
	tween.tween_property(camera, "position", Vector3(0, 0, value), ZOOM_LENGTH).set_trans(
		Tween.TRANS_SINE
	)
	camera_distance = value


func _unhandled_input(event: InputEvent) -> void:
	if event is InputEventMouseButton:
		Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
	elif event is InputEventMouseMotion:
		if Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED:
			camera_motion((event as InputEventMouseMotion).relative)


func camera_motion(motion: Vector2) -> void:
	if not control_disabled and phase == Phase.AIM:
		# Can only control camera while aiming
		_target_rotation.y = _target_rotation.y - deg_to_rad(motion.x * x_sensitivity)
		_target_rotation.x = clampf(
			_target_rotation.x - deg_to_rad(motion.y * y_sensitivity) * (-1 if invert_pitch else 1),
			PITCH_MIN,
			PITCH_MAX
		)


func take_shot() -> void:
	print("WHACK!")
	print("Power: ", power_bar.value)
	print("Curve: ", curve_bar.value)


func _on_phase_change(new_phase: Phase) -> void:
	match new_phase:
		Phase.AIM:
			print("AIM PHASE")
			power_bar.hide()
			curve_bar.hide()
		Phase.POWER_ADJUST:
			curve_bar.hide()

			power_bar.show()
			power_animation.stop()  # Reset if needed
		Phase.CURVE_ADJUST:
			curve_bar.show()
			curve_animation.play("fill")
		Phase.SHOT:
			power_bar.hide()
			curve_bar.hide()
			take_shot()


func insert_free_cam() -> void:
	_free_camera = FreeCamera.create(camera)
	add_sibling(_free_camera)
	control_disabled = true


func return_free_cam() -> void:
	# TODO alter shot aim based on free camera selection
	_free_camera.queue_free()
	_free_camera = null
	control_disabled = false
	_returning_free_camera = false


func _process(delta: float) -> void:
	# Rotation
	direction.rotation.y = lerp_angle(
		direction.rotation.y, _target_rotation.y, delta * x_acceleration
	)
	pitch.rotation.x = lerp_angle(pitch.rotation.x, _target_rotation.x, delta * y_acceleration)

	arrow.rotation.y = lerp_angle(arrow.rotation.y, _target_rotation.y, delta * ARROW_ACCELERATION)

	# Input Handling
	if control_disabled:
		if Input.is_action_just_pressed("camera_cancel"):
			if is_instance_valid(_free_camera) and not _returning_free_camera:
				_returning_free_camera = true
				var tween := get_tree().create_tween()
				(
					tween
					. tween_property(
						_free_camera,
						"global_transform",
						camera.global_transform,
						FREE_CAM_RETURN_TIME
					)
					. set_trans(Tween.TRANS_SINE)
				)
				tween.tween_callback(return_free_cam)
		return

	match phase:
		Phase.AIM:
			# Camera zoom
			if Input.is_action_just_pressed("shot_zoom_in"):
				camera_distance = max(camera_distance - 1.0, ZOOM_MIN)
			if Input.is_action_just_pressed("shot_zoom_out"):
				camera_distance = min(camera_distance + 1.0, ZOOM_MAX)

			# Switch to free cam
			if (
				Input.is_action_just_pressed("camera_back")
				or Input.is_action_just_pressed("camera_forward")
				or Input.is_action_just_pressed("camera_left")
				or Input.is_action_just_pressed("camera_right")
			):
				insert_free_cam()

			# Advance to next phase
			if Input.is_action_just_pressed("shot_accept"):
				phase = Phase.POWER_ADJUST
		Phase.POWER_ADJUST:
			if Input.is_action_just_pressed("shot_accept"):
				# TODO set power gauge parameters if needed
				power_animation.play("fill")
			if Input.is_action_just_released("shot_accept") and power_bar.value > 0:
				power_animation.pause()
				phase = Phase.CURVE_ADJUST
		Phase.CURVE_ADJUST:
			if Input.is_action_just_pressed("shot_accept"):
				curve_animation.pause()
				phase = Phase.SHOT
		Phase.SHOT:
			# DEBUG: reset to AIM phase
			phase = Phase.AIM
