extends CanvasLayer

var _interactables: Array[Node] = []
var _active_interactable: Node = null
var _dialog_visible := false
var _dialog_source: Node = null

var _prompt_label: Label
var _dialog_panel: PanelContainer
var _dialog_label: RichTextLabel

func _ready() -> void:
	layer = 50
	process_mode = Node.PROCESS_MODE_ALWAYS
	_setup_ui()
	_set_dialog_visible(false)
	_update_prompt_visibility()


func _process(_delta: float) -> void:
	if Input.is_action_just_pressed("interact"):
		if _dialog_visible:
			_set_dialog_visible(false)
			return
		if _active_interactable != null:
			_open_dialog_for(_active_interactable)


func register_interactable(interactable: Node) -> void:
	if interactable == null:
		return
	if _interactables.has(interactable):
		return
	_interactables.append(interactable)
	_refresh_active_interactable()


func unregister_interactable(interactable: Node) -> void:
	if interactable == null:
		return
	_interactables.erase(interactable)
	_refresh_active_interactable()


func _refresh_active_interactable() -> void:
	while _interactables.size() > 0 and not is_instance_valid(_interactables[_interactables.size() - 1]):
		_interactables.pop_back()
	_active_interactable = _interactables[_interactables.size() - 1] if _interactables.size() > 0 else null
	_update_prompt_visibility()


func _open_dialog_for(interactable: Node) -> void:
	if _dialog_label:
		_dialog_label.text = _get_dialog_text(interactable)
	_dialog_source = interactable
	_set_dialog_visible(true)


func show_text(text: String) -> void:
	if _dialog_label:
		_dialog_label.text = text
	_dialog_source = null
	_set_dialog_visible(true)


func show_text_from(source: Node, text: String) -> void:
	if _dialog_label:
		_dialog_label.text = text
	_dialog_source = source
	_set_dialog_visible(true)


func close_if_text(expected_text: String) -> void:
	if not _dialog_visible:
		return
	if _dialog_label == null:
		return
	if _dialog_label.text != expected_text:
		return
	_set_dialog_visible(false)


func is_dialog_open() -> bool:
	return _dialog_visible


func is_dialog_open_from(source: Node) -> bool:
	return _dialog_visible and _dialog_source == source


func close_if_source(source: Node) -> void:
	if not _dialog_visible:
		return
	if _dialog_source != source:
		return
	_set_dialog_visible(false)


func _set_dialog_visible(dialog_open: bool) -> void:
	_dialog_visible = dialog_open
	if not _dialog_visible:
		_dialog_source = null
	if _dialog_panel:
		_dialog_panel.visible = _dialog_visible
	_update_prompt_visibility()


func _update_prompt_visibility() -> void:
	if _prompt_label == null:
		return
	var has_active := _active_interactable != null
	_prompt_label.visible = has_active and not _dialog_visible
	if _prompt_label.visible:
		_prompt_label.text = _get_prompt_text(_active_interactable)


func _get_prompt_text(interactable: Node) -> String:
	if interactable == null:
		return ""
	if interactable.has_method("get_dialog_prompt"):
		return String(interactable.call("get_dialog_prompt"))
	return "Press E to interact"


func _get_dialog_text(interactable: Node) -> String:
	if interactable == null:
		return ""
	if interactable.has_method("get_dialog_text"):
		return String(interactable.call("get_dialog_text"))
	return "..."


func _setup_ui() -> void:
	var root := Control.new()
	root.name = "DialogRoot"
	root.set_anchors_preset(Control.PRESET_FULL_RECT)
	root.mouse_filter = Control.MOUSE_FILTER_IGNORE
	add_child(root)

	_prompt_label = Label.new()
	_prompt_label.name = "PromptLabel"
	_prompt_label.set_anchors_preset(Control.PRESET_CENTER_BOTTOM)
	_prompt_label.offset_left = -140.0
	_prompt_label.offset_top = -64.0
	_prompt_label.offset_right = 140.0
	_prompt_label.offset_bottom = -36.0
	_prompt_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
	_prompt_label.mouse_filter = Control.MOUSE_FILTER_IGNORE
	_prompt_label.text = "Press E to interact"
	root.add_child(_prompt_label)

	_dialog_panel = PanelContainer.new()
	_dialog_panel.name = "DialogPanel"
	_dialog_panel.visible = false
	_dialog_panel.set_anchors_preset(Control.PRESET_CENTER_BOTTOM)
	_dialog_panel.offset_left = -300.0
	_dialog_panel.offset_top = -220.0
	_dialog_panel.offset_right = 300.0
	_dialog_panel.offset_bottom = -80.0
	_dialog_panel.mouse_filter = Control.MOUSE_FILTER_IGNORE
	root.add_child(_dialog_panel)

	_dialog_label = RichTextLabel.new()
	_dialog_label.name = "DialogText"
	_dialog_label.custom_minimum_size = Vector2(560.0, 120.0)
	_dialog_label.fit_content = true
	_dialog_label.scroll_active = false
	_dialog_label.bbcode_enabled = true
	_dialog_label.text = ""
	_dialog_panel.add_child(_dialog_label)
