class_name UpgradeMenu
extends Control

signal menu_closed

@onready var list: VBoxContainer = %UpgradeList
@onready var close_button: Button = %CloseButton
var upgrade_buttons: Array[Button] = []
var refresh_queued := false

func _ready() -> void:
	close_button.pressed.connect(close)
	close_button.mouse_entered.connect(close_button.grab_focus)
	GameState.state_changed.connect(_queue_refresh)
	build_list()

func _queue_refresh() -> void:
	if refresh_queued:
		return
	refresh_queued = true
	call_deferred("_refresh_from_state")

func _refresh_from_state() -> void:
	refresh_queued = false
	build_list()

func open() -> void:
	visible = true
	build_list()
	call_deferred("_focus_first_available")

func close() -> void:
	if not visible:
		return
	visible = false
	menu_closed.emit()

func _input(event: InputEvent) -> void:
	if not visible:
		return
	if event.is_action_pressed("pause") or event.is_action_pressed("ui_cancel"):
		close()
		get_viewport().set_input_as_handled()
		return
	if event is InputEventMouseButton:
		return
	if event.is_action_pressed("move_up") or event.is_action_pressed("ui_up"):
		_navigate(-1)
		get_viewport().set_input_as_handled()
	elif event.is_action_pressed("move_down") or event.is_action_pressed("ui_down"):
		_navigate(1)
		get_viewport().set_input_as_handled()
	elif event.is_action_pressed("action") or event.is_action_pressed("ui_accept"):
		_confirm_focused()
		get_viewport().set_input_as_handled()

func build_list() -> void:
	if list == null:
		return
	upgrade_buttons.clear()
	for child: Node in list.get_children():
		list.remove_child(child)
		child.queue_free()
	for id: String in DataCatalog.UPGRADES:
		var upgrade: Dictionary = DataCatalog.UPGRADES[id]
		var button := Button.new()
		button.custom_minimum_size = Vector2(520, 46)
		if GameState.has_upgrade(id):
			button.text = "✓ %s — %s" % [upgrade.display_name, upgrade.description]
			button.disabled = true
		else:
			button.text = "%s — %s — %d coins" % [upgrade.display_name, upgrade.description, upgrade.cost]
			var required_upgrade := str(upgrade.get("requires", ""))
			var missing_requirement := not required_upgrade.is_empty() and not GameState.has_upgrade(required_upgrade)
			button.disabled = GameState.coins < int(upgrade.cost) or missing_requirement
			if missing_requirement:
				button.tooltip_text = "Requires %s" % DataCatalog.UPGRADES[required_upgrade].display_name
			button.pressed.connect(_purchase.bind(id))
		button.mouse_entered.connect(button.grab_focus)
		list.add_child(button)
		upgrade_buttons.append(button)
	if visible:
		call_deferred("_focus_first_available")

func _focus_first_available() -> void:
	for button: Button in upgrade_buttons:
		if is_instance_valid(button) and not button.disabled:
			button.grab_focus()
			return
	close_button.grab_focus()

func _navigate(direction: int) -> void:
	var available := _get_navigation_buttons()
	if available.is_empty():
		return
	var focused := get_viewport().gui_get_focus_owner() as Button
	var index := available.find(focused)
	if index < 0:
		index = 0 if direction > 0 else available.size() - 1
	else:
		index = wrapi(index + direction, 0, available.size())
	available[index].grab_focus()

func _get_navigation_buttons() -> Array[Button]:
	var available: Array[Button] = []
	for button: Button in upgrade_buttons:
		if is_instance_valid(button) and not button.disabled:
			available.append(button)
	available.append(close_button)
	return available

func _confirm_focused() -> void:
	var focused := get_viewport().gui_get_focus_owner() as Button
	if focused == close_button:
		close_button.pressed.emit()
	elif focused != null and upgrade_buttons.has(focused) and not focused.disabled:
		focused.pressed.emit()
	else:
		_focus_first_available()

func _purchase(id: String) -> void:
	GameState.purchase_upgrade(id)
