class_name TitleConfirmationBubblePage
extends Control

signal confirmed
signal cancelled

@export var cluster_path: NodePath = ^"BubbleCluster"
@export var prompt_path: NodePath = ^"BubbleCluster/PromptBubble"
@export var prompt_label_path: NodePath = ^"BubbleCluster/PromptBubble/PromptLabel"
@export var confirm_path: NodePath = ^"BubbleCluster/ConfirmButton"
@export var confirm_label_path: NodePath = (
	^"BubbleCluster/ConfirmButton/ConfirmLabel"
)
@export var cancel_path: NodePath = ^"BubbleCluster/CancelButton"
@export var multiline_confirm_neutral_size: Vector2 = Vector2(116.0, 116.0)
@export var multiline_confirm_compact_minimum_size: Vector2 = (
	Vector2(90.0, 90.0)
)
@export var compact_height_threshold: float = 250.0
@export_range(0.0, 128.0, 1.0) var transition_safe_margin: float = 24.0

var _cluster: BubbleCluster
var _prompt: BubbleButton
var _prompt_label: Label
var _confirm_button: BubbleButton
var _confirm_label: Label
var _cancel_button: BubbleButton
var _default_confirm_neutral_size: Vector2
var _default_confirm_compact_minimum_size: Vector2
var _bubbles: Array[BubbleButton] = []
var _resting_cluster_position: Vector2 = Vector2.ZERO
var _transition: Tween
var _transition_generation: int = 0
var _is_transitioning: bool = false


func _ready() -> void:
	_cluster = get_node(cluster_path) as BubbleCluster
	_prompt = get_node(prompt_path) as BubbleButton
	_prompt_label = get_node(prompt_label_path) as Label
	_confirm_button = get_node(confirm_path) as BubbleButton
	_confirm_label = get_node(confirm_label_path) as Label
	_cancel_button = get_node(cancel_path) as BubbleButton
	_default_confirm_neutral_size = _confirm_button.neutral_size
	_default_confirm_compact_minimum_size = (
		_confirm_button.compact_minimum_size
	)
	_bubbles = [_prompt, _confirm_button, _cancel_button]
	_cluster.configure(_bubbles)
	_prompt.focus_mode = Control.FOCUS_NONE
	_prompt.mouse_filter = Control.MOUSE_FILTER_IGNORE
	_confirm_button.pressed.connect(confirmed.emit)
	_cancel_button.pressed.connect(cancelled.emit)
	_configure_focus()
	hide_page()


func configure(
	prompt_text: String,
	confirm_text: String,
	use_multiline_action_layout: bool = false,
) -> void:
	_prompt_label.text = prompt_text
	if use_multiline_action_layout:
		_confirm_button.text = ""
		_confirm_label.text = confirm_text
		_confirm_label.show()
		_confirm_button.label_control_path = ^"ConfirmLabel"
	else:
		_confirm_label.text = ""
		_confirm_label.hide()
		_confirm_button.label_control_path = NodePath()
		_confirm_button.text = confirm_text
	_confirm_button.apply_profile()
	_confirm_button.neutral_size = (
		multiline_confirm_neutral_size
		if use_multiline_action_layout
		else _default_confirm_neutral_size
	)
	_confirm_button.compact_minimum_size = (
		multiline_confirm_compact_minimum_size
		if use_multiline_action_layout
		else _default_confirm_compact_minimum_size
	)


func set_stage_rect(stage_rect: Rect2) -> void:
	if not is_node_ready():
		return
	var field_size := Vector2(
		maxf(1.0, stage_rect.size.x),
		maxf(1.0, stage_rect.size.y)
	)
	_resting_cluster_position = stage_rect.position
	_cluster.size = field_size
	_cluster.apply_layout(
		field_size,
		false
	)
	if not _is_transitioning:
		_cluster.position = _resting_cluster_position


func transition_in(
	duration: float,
	completed: Callable,
) -> void:
	_transition_generation += 1
	_cancel_transition()
	show()
	_is_transitioning = true
	_set_interactive(false)
	set_process(true)
	_cluster.position = Vector2(
		_resting_cluster_position.x,
		size.y + transition_safe_margin
	)
	var generation: int = _transition_generation
	_transition = create_tween()
	_transition.tween_property(
		_cluster,
		"position",
		_resting_cluster_position,
		duration
	).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN_OUT)
	_transition.finished.connect(
		_finish_transition_in.bind(generation, completed),
		CONNECT_ONE_SHOT
	)


func transition_out(
	duration: float,
	completed: Callable,
) -> void:
	if not visible or _is_transitioning:
		return
	_transition_generation += 1
	_cancel_transition()
	_is_transitioning = true
	_set_interactive(false)
	var generation: int = _transition_generation
	_transition = create_tween()
	_transition.tween_property(
		_cluster,
		"position:y",
		-_cluster.size.y - transition_safe_margin,
		duration
	).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN_OUT)
	_transition.finished.connect(
		_finish_transition_out.bind(generation, completed),
		CONNECT_ONE_SHOT
	)


func hide_page() -> void:
	_transition_generation += 1
	_cancel_transition()
	_is_transitioning = false
	_set_interactive(false)
	set_process(false)
	hide()
	if _cluster != null:
		_cluster.position = _resting_cluster_position


func lock_interaction() -> void:
	_set_interactive(false)


func is_transitioning() -> bool:
	return _is_transitioning


func focus_confirm() -> void:
	if (
		_confirm_button.visible
		and _confirm_button.focus_mode != Control.FOCUS_NONE
	):
		_confirm_button.grab_focus()


func _process(delta: float) -> void:
	if visible:
		_cluster.advance_motion(delta)


func _configure_focus() -> void:
	_confirm_button.focus_neighbor_left = _confirm_button.get_path_to(
		_cancel_button
	)
	_confirm_button.focus_neighbor_right = _confirm_button.focus_neighbor_left
	_confirm_button.focus_neighbor_top = _confirm_button.focus_neighbor_left
	_confirm_button.focus_neighbor_bottom = _confirm_button.focus_neighbor_left
	_cancel_button.focus_neighbor_left = _cancel_button.get_path_to(
		_confirm_button
	)
	_cancel_button.focus_neighbor_right = _cancel_button.focus_neighbor_left
	_cancel_button.focus_neighbor_top = _cancel_button.focus_neighbor_left
	_cancel_button.focus_neighbor_bottom = _cancel_button.focus_neighbor_left


func _set_interactive(interactive: bool) -> void:
	mouse_filter = (
		Control.MOUSE_FILTER_PASS
		if interactive
		else Control.MOUSE_FILTER_IGNORE
	)
	for bubble: BubbleButton in [_confirm_button, _cancel_button]:
		if bubble == null:
			continue
		bubble.focus_mode = (
			Control.FOCUS_ALL if interactive else Control.FOCUS_NONE
		)
		bubble.mouse_filter = (
			Control.MOUSE_FILTER_STOP
			if interactive
			else Control.MOUSE_FILTER_IGNORE
		)


func _finish_transition_in(
	generation: int,
	completed: Callable,
) -> void:
	if generation != _transition_generation or not visible:
		return
	_transition = null
	_is_transitioning = false
	_set_interactive(true)
	focus_confirm()
	completed.call()


func _finish_transition_out(
	generation: int,
	completed: Callable,
) -> void:
	if generation != _transition_generation or not visible:
		return
	_transition = null
	_is_transitioning = false
	hide()
	_cluster.position = _resting_cluster_position
	set_process(false)
	completed.call()


func _cancel_transition() -> void:
	if _transition != null:
		_transition.kill()
		_transition = null
