class_name Focus
extends Camera2D
# Transition to next slide and focus current slide


signal ended

enum Transit {
	BEAM,
	SMOOTH,
}

@export_group("Tween caracteristics", "tween_")
@export var tween_is_parallel: bool = false

@export_group("Move", "move_")
@export var move_duration: float = 1.0
@export var move_trans: Tween.TransitionType = Tween.TRANS_SINE
@export var move_ease: Tween.EaseType = Tween.EASE_IN_OUT

@export_group("Scope", "scope_")
@export var scope_duration: float = 1.0
@export var scope_trans: Tween.TransitionType = Tween.TRANS_SINE
@export var scope_closer_ease: Tween.EaseType = Tween.EASE_IN
@export var scope_wider_ease: Tween.EaseType = Tween.EASE_OUT

var tween: Tween
var scope: Vector2 : get = get_scope, set = set_scope

var target_pos: Vector2 = Vector2.ZERO
var target_scope: Vector2 = Vector2.ONE


func focus_on(pos: Vector2, scalar_scale: float, trans: Transit) -> void:
	target_pos = pos
	target_scope = Vector2.ONE * scalar_scale

	if Transit.BEAM == trans:
		_beam_to_focus()
	elif Transit.SMOOTH == trans:
		_smooth_transit_to_focus()
	else:
		assert(false, "Trans %s is not implemented." % trans)


func end() -> void:
	ended.emit()


func get_scope() -> Vector2:
	return _invert_vector(get_zoom())


func set_scope(new_scope: Vector2) -> void:
	set_zoom(_invert_vector(new_scope))


func _beam_to_focus() -> void:
	_abort_ongoing_transit()

	set_position(target_pos)
	set_scope(target_scope)


func _smooth_transit_to_focus() -> void:
	_abort_ongoing_transit()

	var is_wider: bool = target_scope.x > get_scope().x
	var scope_ease: Tween.EaseType = scope_wider_ease if is_wider else scope_closer_ease

	tween = create_tween().set_parallel(tween_is_parallel)
	tween.tween_property(self, "position", target_pos, move_duration).set_trans(move_trans).set_ease(move_ease)
	tween.tween_property(self, "scope", target_scope, scope_duration).set_trans(scope_trans).set_ease(scope_ease)
	tween.tween_callback(end)


func _abort_ongoing_transit() -> void:
	if tween:
		tween.kill()


func _invert_vector(vec: Vector2) -> Vector2:
	assert(vec.x > 0)
	assert(vec.y > 0)
	return Vector2(1.0 / vec.x, 1.0 / vec.y)
