extends Camera3D

@export var height: float = 28.0
@export var horizontal_distance: float = 28.0
@export var horizontal_angle_deg: float = 45.0

@export var size_min: float = 5.0
@export var size_max: float = 30.0
@export var default_size: float = 15.0

@export var focus_slice_thickness: float = 6.0
@export var blur_transition: float = 15.0

var _shake_amount: float = 0.0
var _shake_decay:  float = 0.0
var _user_size:    float = 0.0
var _charge_active: bool = false


func _ready() -> void:
	set_as_top_level(true)
	projection = Camera3D.PROJECTION_ORTHOGONAL
	_user_size = default_size
	size = default_size
	near = 0.1
	far  = 150.0


func _unhandled_input(event: InputEvent) -> void:
	if event.is_action_pressed("zoom_in"):
		_user_size = clamp(_user_size / 1.2, size_min, size_max)
	if event.is_action_pressed("zoom_out"):
		_user_size = clamp(_user_size * 1.2, size_min, size_max)


func _process(delta: float) -> void:
	var zoom_target := _user_size * DP.f("charge_zoom_factor") if _charge_active else _user_size
	size = lerpf(size, zoom_target, delta * 8.0)

	var angle_rad := deg_to_rad(horizontal_angle_deg)
	var offset := Vector3(
		sin(angle_rad) * horizontal_distance,
		height,
		cos(angle_rad) * horizontal_distance,
	)
	var target := get_parent() as Node3D
	global_position = target.global_position + offset
	look_at(target.global_position, Vector3.UP)

	_update_ortho_tilt_shift_dof(target.global_position)

	if _shake_amount > 0.005:
		global_position += Vector3(
			randf_range(-_shake_amount, _shake_amount),
			randf_range(-_shake_amount * 0.25, _shake_amount * 0.25),
			randf_range(-_shake_amount, _shake_amount),
		)
		_shake_amount = move_toward(_shake_amount, 0.0, _shake_decay * delta)


func trigger_hit(strength: float) -> void:
	_shake_amount = strength * 0.5
	_shake_decay  = _shake_amount / 0.4


func set_charge_active(active: bool) -> void:
	_charge_active = active


func _update_ortho_tilt_shift_dof(target_pos: Vector3) -> void:
	var cam_attr: CameraAttributesPractical = null

	if "attributes" in self and self.attributes is CameraAttributesPractical:
		cam_attr = self.attributes
	elif "camera_attributes" in self and self.camera_attributes is CameraAttributesPractical:
		cam_attr = self.camera_attributes

	if cam_attr != null:
		var to_target := target_pos - global_position
		var forward_vector := -global_transform.basis.z
		var ortho_depth := to_target.dot(forward_vector)

		var zoom_factor := size / default_size
		var dynamic_slice := focus_slice_thickness * zoom_factor
		var half_slice := dynamic_slice * 0.5

		var base_transition := blur_transition * zoom_factor

		cam_attr.dof_blur_far_distance  = ortho_depth + half_slice
		cam_attr.dof_blur_near_distance = maxf(near + 0.1, ortho_depth - half_slice)
		cam_attr.dof_blur_far_transition  = maxf(0.1, base_transition * 0.5)
		cam_attr.dof_blur_near_transition = maxf(1.0, base_transition * 1.5)
		cam_attr.dof_blur_far_enabled  = false
		cam_attr.dof_blur_near_enabled = false
