extends CanvasLayer

# Minimalistic Inventory UI with Stats Panel
# Toggle with Tab key, shows stats, equipment slots and inventory items
# Uses inventory_slot graphics like inspiration inventory system
# Supports keyboard navigation with arrow keys

var is_open: bool = false
var local_player: Node = null
var is_updating_ui: bool = false # Prevent recursive UI updates

# Selection tracking
var selected_item: Item = null # Selected inventory item
var selected_slot: String = "" # Selected equipment slot name
var selected_type: String = "" # "item" or "equipment"
var is_first_open: bool = true # Track if this is the first time opening

# Navigation tracking (for keyboard navigation)
var inventory_selection_row: int = 0 # Current inventory row (0-based)
var inventory_selection_col: int = 0 # Current inventory column (0-based)
var equipment_selection_index: int = 0 # Current equipment slot index (0-5: mainhand, offhand, headgear, armour, boots, accessory)

# UI Nodes (from scene)
@onready var container: Control = $InventoryContainer
@onready var stats_panel: Control = $InventoryContainer/MarginContainer/MarginContainer/VBoxContainer/HBox/StatsPanel
@onready var equipment_panel: GridContainer = $InventoryContainer/MarginContainer/MarginContainer/VBoxContainer/HBox/InventoryPanel/EquipmentPanel
@onready var scroll_container: ScrollContainer = $InventoryContainer/MarginContainer/MarginContainer/VBoxContainer/HBox/InventoryPanel/InventoryScroll
@onready var inventory_grid: VBoxContainer = $InventoryContainer/MarginContainer/MarginContainer/VBoxContainer/HBox/InventoryPanel/InventoryScroll/InventoryVBox
@onready var selection_rectangle: Panel = $InventoryContainer/MarginContainer/MarginContainer/VBoxContainer/SelectionRectangle
@onready var info_panel: Control = $InventoryContainer/MarginContainer/MarginContainer/VBoxContainer/InfoPanel
@onready var info_label: Label = $InventoryContainer/MarginContainer/MarginContainer/VBoxContainer/InfoPanel/InfoLabel
@onready var stats_label: Label = $InventoryContainer/MarginContainer/MarginContainer/VBoxContainer/HBox/StatsPanel/StatsLabel
@onready var label_base_stats: Label = $InventoryContainer/MarginContainer/MarginContainer/VBoxContainer/HBox/StatsPanel/StatsHBox/LabelBaseStats
@onready var label_base_stats_value: Label = $InventoryContainer/MarginContainer/MarginContainer/VBoxContainer/HBox/StatsPanel/StatsHBox/LabelBaseStatsValue
@onready var label_derived_stats: Label = $InventoryContainer/MarginContainer/MarginContainer/VBoxContainer/HBox/StatsPanel/StatsHBox/LabelDerivedStats
@onready var label_derived_stats_value: Label = $InventoryContainer/MarginContainer/MarginContainer/VBoxContainer/HBox/StatsPanel/StatsHBox/LabelDerivedStatsValue
@onready var sfx_potion: AudioStreamPlayer2D = $SfxPotion
@onready var sfx_food: AudioStreamPlayer2D = $SfxFood
@onready var sfx_armour: AudioStreamPlayer2D = $SfxArmour

# Bar layout constants (align X/Y + bar across rows)
const _BAR_WIDTH: int = 100
const _BAR_VALUE_MIN_WIDTH: int = 44  # "999/999"
const _BAR_LABEL_MIN_WIDTH: int = 52  # "Weight:", "Exp:", "HP:", "MP:", "Coin:"

# Weight UI elements (created programmatically)
var weight_container: HBoxContainer = null
var weight_label: Label = null
var weight_value_label: Label = null
var weight_progress_bar: ProgressBar = null

# Exp UI elements (like weight)
var exp_container: HBoxContainer = null
var exp_label: Label = null
var exp_value_label: Label = null
var exp_progress_bar: ProgressBar = null

# HP / MP bar elements
var hp_container: HBoxContainer = null
var hp_label: Label = null
var hp_value_label: Label = null
var hp_progress_bar: ProgressBar = null
var mp_container: HBoxContainer = null
var mp_label: Label = null
var mp_value_label: Label = null
var mp_progress_bar: ProgressBar = null

# Coin UI elements ("Coin:" + 6-frame sprite + "X N")
var coin_container: HBoxContainer = null
var coin_label: Label = null
var coin_sprite: Sprite2D = null
var coin_value_label: Label = null
var coin_anim_time: float = 0.0

# Store button/item mappings for selection highlighting
var inventory_buttons: Dictionary = {} # item -> button
var equipment_buttons: Dictionary = {} # slot_name -> button
var inventory_items_list: Array = [] # Flat list of items for navigation
var inventory_rows_list: Array = [] # List of HBoxContainers (rows)

# Level-up stat allocation (when pending_level_up)
var level_up_label: Label = null
var level_up_stat_buttons: Array = [] # Buttons for STR, DEX, INT, END, WIS, LCK, PER
var level_up_stat_container: HBoxContainer = null
var selected_level_up_stat_index: int = -1
const STAT_DESCRIPTIONS: Dictionary = {
	"str": "STR (Strength): Increases melee and bow damage. Raises carry capacity so you can hold more items before becoming encumbered.",
	"dex": "DEX (Dexterity): Improves dodge chance and hit chance. Makes you move and attack faster.",
	"int": "INT (Intelligence): Boosts spell damage (flames, frost, heal). Increases max mana and vision range.",
	"end": "END (Endurance): Increases max HP. Each point raises your maximum health.",
	"wis": "WIS (Wisdom): Improves mana regeneration and resistances to certain effects.",
	"lck": "LCK (Luck): Increases critical hit chance. Critical hits deal bonus damage and partially ignore defense.",
	"per": "PER (Perception): Improves trap detection and perception. Helps you spot hazards and secrets."
}

# Equipment slot buttons
var equipment_slots: Dictionary = {
	"mainhand": null,
	"offhand": null,
	"headgear": null,
	"armour": null,
	"boots": null,
	"accessory": null
}
var equipment_slots_list: Array = ["mainhand", "offhand", "headgear", "armour", "boots", "accessory"] # Order for navigation

# StyleBoxes for inventory slots (like inspiration system)
var style_box_hover: StyleBox = null
var style_box_focused: StyleBox = null
var style_box_pressed: StyleBox = null
var style_box_empty: StyleBox = null
var quantity_font: Font = null

# Selection animation
var selection_animation_time: float = 0.0

func _ready():
	# Set layer to be above game but below chat
	layer = 150
	
	# Load styleboxes for inventory slots (like inspiration system)
	_setup_styleboxes()
		
	# Create equipment slot buttons (dynamically)
	_create_equipment_slots()
	
	# Create HP/MP bars, then weight, exp, coin (order in stats panel)
	_create_hp_ui()
	_create_mp_ui()
	_create_weight_ui()
	_create_exp_ui()
	_create_coin_ui()
	
	# Level-up stat allocation UI (label + stat buttons)
	_setup_level_up_ui()
	
	# Setup selection rectangle (already in scene, just configure it)
	_setup_selection_rectangle()
	
	# Find local player
	call_deferred("_find_local_player")

func _setup_styleboxes():
	# Create styleboxes exactly like inspiration inventory system
	var selected_tex = preload("res://assets/gfx/ui/inventory_slot_kenny_white.png")
	
	style_box_empty = StyleBoxEmpty.new()
	
	if selected_tex:
		# Scale factor for the slot background (1.5x to match larger item sprites)
		# Since StyleBoxTexture doesn't support texture_scale, we use expand_margin
		# to make the texture fill more space
		# For 1.5x scale on a 36px button (which was 24px originally), we need to expand
		# The button is now 36px, so to make a 24px texture appear 1.5x (36px), we use negative margins
		# Actually, let's use smaller positive margins to avoid clipping
		var margin_scale = 3.0 # Smaller margin to avoid clipping in upper left corner
		
		style_box_hover = StyleBoxTexture.new()
		style_box_hover.texture = selected_tex
		style_box_hover.expand_margin_left = margin_scale
		style_box_hover.expand_margin_top = margin_scale
		style_box_hover.expand_margin_right = margin_scale
		style_box_hover.expand_margin_bottom = margin_scale
		
		style_box_focused = StyleBoxTexture.new()
		style_box_focused.texture = selected_tex
		style_box_focused.expand_margin_left = margin_scale
		style_box_focused.expand_margin_top = margin_scale
		style_box_focused.expand_margin_right = margin_scale
		style_box_focused.expand_margin_bottom = margin_scale
		
		style_box_pressed = StyleBoxTexture.new()
		style_box_pressed.texture = selected_tex
		style_box_pressed.expand_margin_left = margin_scale
		style_box_pressed.expand_margin_top = margin_scale
		style_box_pressed.expand_margin_right = margin_scale
		style_box_pressed.expand_margin_bottom = margin_scale
	else:
		# Fallback to empty styleboxes if texture not found
		style_box_hover = StyleBoxEmpty.new()
		style_box_focused = StyleBoxEmpty.new()
		style_box_pressed = StyleBoxEmpty.new()
	
	# Load quantity font (dmg_numbers.png)
	if ResourceLoader.exists("res://assets/fonts/dmg_numbers.png"):
		quantity_font = load("res://assets/fonts/dmg_numbers.png")

func _setup_selection_rectangle():
	# Selection rectangle is already in scene, just ensure it's configured correctly
	if selection_rectangle:
		selection_rectangle.visible = false
		# Ensure it's on top and visible
		selection_rectangle.z_index = 100
		selection_rectangle.z_as_relative = false
		selection_rectangle.mouse_filter = Control.MOUSE_FILTER_IGNORE # Don't block mouse input
		# Ensure it's on top
		selection_rectangle.z_index = 100
		selection_rectangle.z_as_relative = false

func _find_local_player():
	# Find the local player
	var game_world = get_tree().get_first_node_in_group("game_world")
	if game_world:
		var player_manager = game_world.get_node_or_null("PlayerManager")
		if player_manager:
			var local_players = player_manager.get_local_players()
			if local_players.size() > 0:
				local_player = local_players[0]
				if local_player and local_player.character_stats:
					# Connect to character_changed signal (for inventory/equipment changes)
					if local_player.character_stats.character_changed.is_connected(_on_character_changed):
						local_player.character_stats.character_changed.disconnect(_on_character_changed)
					local_player.character_stats.character_changed.connect(_on_character_changed)
					# Connect to mana_changed signal (for mana updates only - don't rebuild UI)
					if local_player.character_stats.mana_changed.is_connected(_on_mana_changed):
						local_player.character_stats.mana_changed.disconnect(_on_mana_changed)
					local_player.character_stats.mana_changed.connect(_on_mana_changed)
					# Connect to health_changed signal (for HP updates only - don't rebuild UI)
					if local_player.character_stats.health_changed.is_connected(_on_health_changed):
						local_player.character_stats.health_changed.disconnect(_on_health_changed)
					local_player.character_stats.health_changed.connect(_on_health_changed)
					# Initial update
					_update_ui()
					_update_stats()

func _update_stats():
	if not local_player or not local_player.character_stats:
		return
	
	var char_stats = local_player.character_stats
	
	# Update race/class in stats label
	if stats_label:
		var race_text = char_stats.race
		stats_label.text = "Stats - " + race_text
	
	# Level-up UI: "Level X - LEVEL UP" in green, stat allocation buttons
	var pending = char_stats.pending_level_up and char_stats.pending_stat_points > 0
	if level_up_label:
		level_up_label.visible = pending
		if pending:
			level_up_label.text = "Level " + str(char_stats.level) + " - LEVEL UP"
			level_up_label.add_theme_color_override("font_color", Color(0.2, 1.0, 0.4))
	if level_up_stat_container:
		level_up_stat_container.visible = pending
	
	# Base stats: Level, STR, DEX, END, INT, WIS, LCK, PER (HP/MP are bars below)
	if label_base_stats:
		label_base_stats.text = "Level\n\nSTR\nDEX\nEND\nINT\nWIS\nLCK\nPER"
	if label_base_stats_value:
		label_base_stats_value.text = str(char_stats.level) + "\n\n" + \
			str(char_stats.baseStats.str) + "\n" + \
			str(char_stats.baseStats.dex) + "\n" + \
			str(char_stats.baseStats.end) + "\n" + \
			str(char_stats.baseStats.int) + "\n" + \
			str(char_stats.baseStats.wis) + "\n" + \
			str(char_stats.baseStats.lck) + "\n" + \
			str(char_stats.baseStats.get("per", 10))
	
	# Derived stats: DMG, DEF, MovSpd, AtkSpd, Sight, SpellAmp, Crit% (XP/Coin moved to exp meter & coin UI)
	if label_derived_stats:
		label_derived_stats.text = "DMG\nDEF\nMovSpd\nAtkSpd\nSight\nSpellAmp\nCrit%"
	if label_derived_stats_value:
		label_derived_stats_value.text = "%.1f\n%.1f\n%.2f\n%.2f\n%.1f\n%.1f\n%.1f%%" % [
			char_stats.damage,
			char_stats.defense,
			char_stats.move_speed,
			char_stats.attack_speed,
			char_stats.sight,
			char_stats.spell_amp,
			char_stats.crit_chance
		]
	
	# HP bar
	if hp_progress_bar and hp_value_label:
		hp_progress_bar.max_value = max(1.0, char_stats.maxhp)
		hp_progress_bar.value = char_stats.hp
		hp_value_label.text = str(int(char_stats.hp)) + "/" + str(int(char_stats.maxhp))
	
	# MP bar
	if mp_progress_bar and mp_value_label:
		mp_progress_bar.max_value = max(1.0, char_stats.maxmp)
		mp_progress_bar.value = char_stats.mp
		mp_value_label.text = str(int(char_stats.mp)) + "/" + str(int(char_stats.maxmp))
	
	# Exp meter (like weight)
	if exp_progress_bar and exp_value_label:
		var xp = char_stats.xp
		var xp_next = char_stats.xp_to_next_level
		exp_progress_bar.max_value = max(1.0, xp_next)
		exp_progress_bar.value = xp
		exp_value_label.text = str(int(xp)) + "/" + str(int(xp_next))
		var fill_exp = StyleBoxFlat.new()
		fill_exp.bg_color = Color(0.55, 0.35, 0.95)
		exp_progress_bar.add_theme_stylebox_override("fill", fill_exp)
	
	# Coin: "Coin:" + 6-frame sprite + "X <count>"
	if coin_value_label:
		coin_value_label.text = "X " + str(char_stats.coin)
	
	# Weight progress bar
	if weight_progress_bar and weight_value_label:
		var current_weight = char_stats.get_total_weight()
		var max_weight = char_stats.get_carrying_capacity()
		weight_progress_bar.max_value = max_weight
		weight_progress_bar.value = current_weight
		weight_value_label.text = str(int(current_weight)) + "/" + str(int(max_weight))
		var weight_ratio = current_weight / max_weight
		var fill_style = StyleBoxFlat.new()
		if weight_ratio < 0.7:
			fill_style.bg_color = Color(0.6, 0.8, 0.3)
		elif weight_ratio < 0.9:
			fill_style.bg_color = Color(0.9, 0.8, 0.2)
		else:
			fill_style.bg_color = Color(0.9, 0.3, 0.2)
		weight_progress_bar.add_theme_stylebox_override("fill", fill_style)

func _setup_level_up_ui() -> void:
	if not stats_panel:
		return
	level_up_label = Label.new()
	level_up_label.name = "LevelUpLabel"
	level_up_label.add_theme_font_size_override("font_size", 14)
	level_up_label.add_theme_color_override("font_color", Color(0.2, 1.0, 0.4))
	if ResourceLoader.exists("res://assets/fonts/standard_font.png"):
		var fr = load("res://assets/fonts/standard_font.png")
		if fr:
			level_up_label.add_theme_font_override("font", fr)
	level_up_label.visible = false
	stats_panel.add_child(level_up_label)
	stats_panel.move_child(level_up_label, 1)
	level_up_stat_container = HBoxContainer.new()
	level_up_stat_container.name = "LevelUpStatButtons"
	level_up_stat_container.add_theme_constant_override("separation", 4)
	level_up_stat_container.visible = false
	for stat_name in CharacterStats.LEVEL_UP_STAT_NAMES:
		var btn = Button.new()
		btn.name = "LevelUp_" + stat_name
		btn.text = stat_name.to_upper()
		btn.custom_minimum_size = Vector2(32, 24)
		btn.flat = true
		btn.add_theme_color_override("font_color", Color(0.85, 0.85, 0.85))
		btn.add_theme_color_override("font_hover_color", Color(0.4, 1.0, 0.5))
		btn.add_theme_color_override("font_focus_color", Color(0.4, 1.0, 0.5))
		if ResourceLoader.exists("res://assets/fonts/standard_font.png"):
			var fr = load("res://assets/fonts/standard_font.png")
			if fr:
				btn.add_theme_font_override("font", fr)
		btn.add_theme_font_size_override("font_size", 9)
		btn.focus_mode = Control.FOCUS_ALL
		btn.pressed.connect(_on_level_up_stat_pressed.bind(stat_name))
		btn.mouse_entered.connect(_on_level_up_stat_hover_entered.bind(stat_name))
		btn.mouse_exited.connect(_on_level_up_stat_hover_exited)
		btn.gui_input.connect(_on_level_up_stat_gui_input.bind(stat_name, btn))
		btn.focus_entered.connect(_on_level_up_stat_focus_entered.bind(stat_name))
		level_up_stat_container.add_child(btn)
		level_up_stat_buttons.append(btn)
	stats_panel.add_child(level_up_stat_container)
	stats_panel.move_child(level_up_stat_container, 2)

func _on_level_up_stat_pressed(stat_name: String) -> void:
	if not local_player or not local_player.character_stats:
		return
	if not _can_use_inventory():
		return
	if local_player.character_stats.allocate_stat_point(stat_name):
		if sfx_armour:
			sfx_armour.play()
		_update_stats()
		if not local_player.character_stats.pending_level_up:
			selected_type = "equipment"
			selected_level_up_stat_index = -1
			var next_index = _find_next_filled_equipment_slot(-1, 1)
			if next_index >= 0:
				equipment_selection_index = next_index
				selected_slot = equipment_slots_list[next_index]
				selected_item = local_player.character_stats.equipment[selected_slot]
			else:
				selected_slot = ""
				selected_item = null
				if inventory_items_list.size() > 0:
					selected_type = "item"
					inventory_selection_row = 0
					inventory_selection_col = 0
		_update_ui()

func _on_level_up_stat_hover_entered(stat_name: String) -> void:
	if info_label and stat_name in STAT_DESCRIPTIONS:
		info_label.text = STAT_DESCRIPTIONS[stat_name]

func _on_level_up_stat_hover_exited() -> void:
	if not info_label:
		return
	var fc = get_viewport().gui_get_focus_owner()
	if level_up_stat_container and fc and is_instance_valid(level_up_stat_container) and fc.get_parent() == level_up_stat_container:
		var idx = level_up_stat_buttons.find(fc)
		if idx >= 0 and idx < CharacterStats.LEVEL_UP_STAT_NAMES.size():
			var sn = CharacterStats.LEVEL_UP_STAT_NAMES[idx]
			if sn in STAT_DESCRIPTIONS:
				info_label.text = STAT_DESCRIPTIONS[sn]
				return
	_update_info_panel()

func _on_level_up_stat_focus_entered(stat_name: String) -> void:
	if info_label and stat_name in STAT_DESCRIPTIONS:
		info_label.text = STAT_DESCRIPTIONS[stat_name]

func _on_level_up_stat_gui_input(event: InputEvent, stat_name: String, _btn: Button) -> void:
	if event is InputEventKey and event.pressed and not event.echo:
		if event.keycode == KEY_ENTER or event.keycode == KEY_KP_ENTER or event.keycode == KEY_SPACE:
			_on_level_up_stat_pressed(stat_name)

func _create_equipment_slots():
	# Equipment slot order: mainhand, offhand, headgear, armour, boots, accessory
	var slot_names = ["mainhand", "offhand", "headgear", "armour", "boots", "accessory"]
	var slot_labels = ["Main-hand", "Off-hand", "Head", "Armour", "Boots", "Accessory"]
	
	for i in range(slot_names.size()):
		var slot_name = slot_names[i]
		var slot_label = slot_labels[i]
		
		# Container for slot
		var slot_container = VBoxContainer.new()
		slot_container.name = slot_name + "_slot"
		equipment_panel.add_child(slot_container)
		
		# Label
		var label = Label.new()
		label.text = slot_label
		label.add_theme_font_size_override("font_size", 10)
		label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
		if ResourceLoader.exists("res://assets/fonts/standard_font.png"):
			var font_resource = load("res://assets/fonts/standard_font.png")
			if font_resource:
				label.add_theme_font_override("font", font_resource)
		slot_container.add_child(label)
		
		# Button (use styleboxes like inspiration system)
		var button = Button.new()
		button.name = slot_name + "_btn"
		# Button size increased to accommodate 1.5x scaled texture (24 * 1.5 = 36)
		button.custom_minimum_size = Vector2(36, 36) # Increased to fit 1.5x scaled texture
		button.size = Vector2(36, 36)
		if style_box_empty:
			button.add_theme_stylebox_override("normal", style_box_empty)
		if style_box_hover:
			button.add_theme_stylebox_override("hover", style_box_hover)
		if style_box_focused:
			button.add_theme_stylebox_override("focus", style_box_focused)
		if style_box_pressed:
			button.add_theme_stylebox_override("pressed", style_box_pressed)
		button.flat = false # Use styleboxes instead of flat
		button.focus_mode = Control.FOCUS_ALL # Allow button to receive focus
		button.size_flags_horizontal = 0
		button.size_flags_vertical = 0
		button.connect("pressed", _on_equipment_slot_pressed.bind(slot_name))
		button.connect("gui_input", _on_equipment_slot_gui_input.bind(slot_name))
		# Connect focus_entered like inspiration system (for keyboard navigation)
		if local_player and local_player.character_stats:
			var equipped_item = local_player.character_stats.equipment[slot_name]
			if equipped_item:
				button.connect("focus_entered", _on_equipment_slot_pressed.bind(slot_name))
		slot_container.add_child(button)
		
		equipment_slots[slot_name] = button
		equipment_buttons[slot_name] = button

func _style_bar_font(lbl: Label) -> void:
	lbl.add_theme_font_size_override("font_size", 10)
	if ResourceLoader.exists("res://assets/fonts/standard_font.png"):
		var fr = load("res://assets/fonts/standard_font.png")
		if fr:
			lbl.add_theme_font_override("font", fr)

func _make_progress_bar_background() -> StyleBoxFlat:
	var bg = StyleBoxFlat.new()
	bg.bg_color = Color(0.2, 0.2, 0.2, 0.8)
	bg.border_color = Color(0.4, 0.4, 0.4)
	bg.set_border_width_all(1)
	return bg

func _create_bar_row(p_name: String, p_label_text: String) -> Dictionary:
	var row = HBoxContainer.new()
	row.name = p_name
	row.add_theme_constant_override("separation", 4)
	var left = Label.new()
	left.text = p_label_text
	left.custom_minimum_size.x = _BAR_LABEL_MIN_WIDTH
	_style_bar_font(left)
	var spacer = Control.new()
	spacer.size_flags_horizontal = Control.SIZE_EXPAND_FILL
	var value_lbl = Label.new()
	value_lbl.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT
	value_lbl.custom_minimum_size.x = _BAR_VALUE_MIN_WIDTH
	_style_bar_font(value_lbl)
	var bar = ProgressBar.new()
	bar.custom_minimum_size = Vector2(_BAR_WIDTH, 12)
	bar.show_percentage = false
	bar.add_theme_stylebox_override("background", _make_progress_bar_background())
	row.add_child(left)
	row.add_child(spacer)
	row.add_child(value_lbl)
	row.add_child(bar)
	stats_panel.add_child(row)
	return {"container": row, "label": left, "value_label": value_lbl, "progress_bar": bar}

func _create_hp_ui():
	if not stats_panel:
		return
	var d = _create_bar_row("HPContainer", "HP:")
	hp_container = d.container
	hp_label = d.label
	hp_value_label = d.value_label
	hp_progress_bar = d.progress_bar
	var fill = StyleBoxFlat.new()
	fill.bg_color = Color(0.85, 0.2, 0.2)
	hp_progress_bar.add_theme_stylebox_override("fill", fill)

func _create_mp_ui():
	if not stats_panel:
		return
	var d = _create_bar_row("MPContainer", "MP:")
	mp_container = d.container
	mp_label = d.label
	mp_value_label = d.value_label
	mp_progress_bar = d.progress_bar
	var fill = StyleBoxFlat.new()
	fill.bg_color = Color(0.25, 0.45, 0.9)
	mp_progress_bar.add_theme_stylebox_override("fill", fill)

func _create_weight_ui():
	if not stats_panel:
		return
	var d = _create_bar_row("WeightContainer", "Weight:")
	weight_container = d.container
	weight_label = d.label
	weight_value_label = d.value_label
	weight_progress_bar = d.progress_bar
	var fill = StyleBoxFlat.new()
	fill.bg_color = Color(0.6, 0.8, 0.3)
	weight_progress_bar.add_theme_stylebox_override("fill", fill)

func _create_exp_ui():
	if not stats_panel:
		return
	var d = _create_bar_row("ExpContainer", "Exp:")
	exp_container = d.container
	exp_label = d.label
	exp_value_label = d.value_label
	exp_progress_bar = d.progress_bar
	var fill = StyleBoxFlat.new()
	fill.bg_color = Color(0.55, 0.35, 0.95)
	exp_progress_bar.add_theme_stylebox_override("fill", fill)

func _create_coin_ui():
	if not stats_panel:
		return
	coin_container = HBoxContainer.new()
	coin_container.name = "CoinContainer"
	coin_container.add_theme_constant_override("separation", 4)
	coin_label = Label.new()
	coin_label.name = "CoinLabel"
	coin_label.text = "Coin:"
	coin_label.custom_minimum_size.x = _BAR_LABEL_MIN_WIDTH
	_style_bar_font(coin_label)
	coin_container.add_child(coin_label)
	var coin_spacer = Control.new()
	coin_spacer.size_flags_horizontal = Control.SIZE_EXPAND_FILL
	coin_container.add_child(coin_spacer)
	var coin_wrap = Control.new()
	coin_wrap.custom_minimum_size = Vector2(16, 16)
	coin_sprite = Sprite2D.new()
	coin_sprite.name = "CoinSprite"
	var tex = load("res://assets/gfx/pickups/gold_coin.png") as Texture2D
	if tex:
		coin_sprite.texture = tex
		coin_sprite.hframes = 6
		coin_sprite.vframes = 1
		coin_sprite.frame = 0
		coin_sprite.centered = false
		# Scale down to fit; texture may be multi-frame
		var tw = tex.get_width() / 6.0
		var th = tex.get_height()
		if tw > 0 and th > 0:
			var s = min(16.0 / tw, 16.0 / th)
			coin_sprite.scale = Vector2(s, s)
	coin_wrap.add_child(coin_sprite)
	coin_container.add_child(coin_wrap)
	coin_value_label = Label.new()
	coin_value_label.name = "CoinValueLabel"
	coin_value_label.text = "X 0"
	coin_value_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_LEFT
	_style_bar_font(coin_value_label)
	coin_container.add_child(coin_value_label)
	stats_panel.add_child(coin_container)

func _has_equipment_in_slot(slot_name: String) -> bool:
	# Check if there's an item equipped in this slot
	if not local_player or not local_player.character_stats:
		return false
	return local_player.character_stats.equipment[slot_name] != null

func _can_use_inventory() -> bool:
	# Block equip/unequip/use/drop/level-up when dead
	if not local_player:
		return false
	if "is_dead" in local_player and local_player.is_dead:
		return false
	if "is_processing_death" in local_player and local_player.is_processing_death:
		return false
	return true

func _find_next_filled_equipment_slot(start_index: int, direction: int) -> int:
	# Find next filled equipment slot, or -1 if none found
	var current_index = start_index
	for _i in range(equipment_slots_list.size()):
		current_index += direction
		if current_index < 0:
			current_index = equipment_slots_list.size() - 1
		elif current_index >= equipment_slots_list.size():
			current_index = 0
		
		var slot_name = equipment_slots_list[current_index]
		if _has_equipment_in_slot(slot_name):
			return current_index
	return -1

func _on_equipment_slot_pressed(slot_name: String):
	if not local_player or not local_player.character_stats:
		return
	
	# Prevent updates during UI refresh (prevents infinite loops from focus_entered)
	if is_updating_ui:
		return
	
	# Only select if there's an item equipped (same as arrow-key navigation)
	if not _has_equipment_in_slot(slot_name):
		return
	
	# Select this slot (equivalent to arrow-key selecting this equipment)
	selected_slot = slot_name
	selected_item = local_player.character_stats.equipment[slot_name]
	selected_type = "equipment" if selected_item else ""
	
	# Update navigation position
	if slot_name in equipment_slots_list:
		equipment_selection_index = equipment_slots_list.find(slot_name)
	
	_update_selection_highlight()
	_update_selection_rectangle()
	_update_info_panel()

func _on_equipment_slot_gui_input(event: InputEvent, slot_name: String):
	# Handle double-click to unequip
	if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT:
		if event.double_click and event.pressed:
			# Double-click detected - unequip the item
			selected_slot = slot_name
			selected_item = local_player.character_stats.equipment[slot_name] if local_player and local_player.character_stats else null
			selected_type = "equipment" if selected_item else ""
			
			if selected_type == "equipment" and selected_slot != "":
				# Use the same logic as F key to unequip
				_handle_f_key()

func _update_selection_highlight():
	# This function is kept for compatibility but now uses _update_selection_rectangle()
	_update_selection_rectangle()

# Removed _clear_button_highlight and _apply_button_highlight - using focus system instead

func _update_selection_rectangle():
	# Update visual selection indicator - use button focus like inspiration system
	# Hide the old selection rectangle
	if selection_rectangle:
		selection_rectangle.visible = false
	
	# Find and focus the selected button (like inspiration system uses grab_focus())
	var target_button: Button = null
	
	if selected_type == "equipment" and selected_slot != "":
		# Focus equipment slot (only if it has an item)
		if _has_equipment_in_slot(selected_slot):
			target_button = equipment_buttons.get(selected_slot)
	elif selected_type == "item" and inventory_selection_row >= 0 and inventory_selection_row < inventory_rows_list.size():
		# Focus inventory item
		var row = inventory_rows_list[inventory_selection_row]
		if row and inventory_selection_col >= 0 and inventory_selection_col < row.get_child_count():
			target_button = row.get_child(inventory_selection_col) as Button
	
	# Grab focus on selected button (this will automatically show the focus stylebox)
	if target_button:
		if target_button.is_inside_tree():
			# Don't grab focus if button already has focus (prevents infinite loops)
			if target_button.has_focus():
				return
			
			# Ensure button is visible and ready
			if not target_button.visible:
				target_button.visible = true
			# Wait a frame to ensure button is fully ready for focus
			await get_tree().process_frame
			# Check again if already focused (might have changed during await)
			if target_button.has_focus():
				return
			# Ensure button can receive focus
			if target_button.focus_mode == Control.FOCUS_NONE:
				target_button.focus_mode = Control.FOCUS_ALL
			# Try direct grab_focus (only if not already focused)
			if not target_button.has_focus():
				target_button.grab_focus()
				# Also use call_deferred as backup to ensure it's set
				target_button.call_deferred("grab_focus")
				print("InventoryUI: Focus grabbed on button - has_focus: ", target_button.has_focus())
		else:
			# If not in tree yet, wait a frame and try again
			await get_tree().process_frame
			if target_button.is_inside_tree():
				target_button.grab_focus()
				target_button.call_deferred("grab_focus")
				print("InventoryUI: Focus grabbed on button (after wait)")
			else:
				print("InventoryUI: Button still not in tree after wait")
	else:
		print("InventoryUI: No button to focus - selected_type: ", selected_type)

func _process(delta):
	if is_open:
		# Animate selection highlight border color on selected button
		selection_animation_time += delta * 2.0 # Speed of animation
		# Animate between yellow and orange
		var color1 = Color.YELLOW
		var color2 = Color(1.0, 0.7, 0.0) # Orange-yellow
		var t = (sin(selection_animation_time) + 1.0) / 2.0 # 0 to 1
		var animated_color = color1.lerp(color2, t)
		
		# Find the selected button and update its highlight color
		var selected_button: Button = null
		if selected_type == "equipment" and selected_slot != "":
			if _has_equipment_in_slot(selected_slot):
				selected_button = equipment_buttons.get(selected_slot)
		elif selected_type == "item" and inventory_selection_row >= 0 and inventory_selection_row < inventory_rows_list.size():
			var row = inventory_rows_list[inventory_selection_row]
			if row and inventory_selection_col >= 0 and inventory_selection_col < row.get_child_count():
				selected_button = row.get_child(inventory_selection_col) as Button
		
		if selected_button and selected_button.has_meta("highlight_stylebox"):
			var stylebox = selected_button.get_meta("highlight_stylebox") as StyleBoxFlat
			if stylebox:
				stylebox.border_color = animated_color
		
		# Animate 6-frame coin sprite
		if coin_sprite and coin_sprite.hframes >= 6:
			coin_anim_time += delta * 10.0
			coin_sprite.frame = int(coin_anim_time) % 6

func _update_ui():
	if not local_player or not local_player.character_stats:
		return
	
	# Prevent recursive updates
	if is_updating_ui:
		return
	is_updating_ui = true
	
	var char_stats = local_player.character_stats
	
	# Ensure containers don't clip their children (allows expand_margin to show properly)
	if scroll_container:
		scroll_container.clip_contents = false # Allow buttons to extend beyond scroll bounds
	if inventory_grid:
		inventory_grid.clip_contents = false # Allow buttons to extend beyond grid bounds
	if equipment_panel:
		equipment_panel.clip_contents = false # Allow buttons to extend beyond grid bounds
	
	# Debug: Print inventory contents
	print("InventoryUI: Updating UI - inventory size: ", char_stats.inventory.size())
	for i in range(char_stats.inventory.size()):
		var item = char_stats.inventory[i]
		print("  Item ", i, ": ", item.item_name if item else "null")
	
	# Clear button mappings
	inventory_buttons.clear()
	inventory_items_list.clear()
	inventory_rows_list.clear()
	
	# Wait for old buttons to be fully freed before creating new ones
	await get_tree().process_frame
	
	# Update equipment slots
	for slot_name in equipment_slots.keys():
		var button = equipment_slots[slot_name]
		if not button:
			continue
		
		# Clear existing children (sprite, highlight)
		for child in button.get_children():
			child.queue_free()
		
		var equipped_item = char_stats.equipment[slot_name]
		if equipped_item:
			var sprite = Sprite2D.new()
			# Equipment slots should ONLY use spritePath (items_n_shit.png), NOT equipmentPath
			# equipmentPath is for character rendering only!
			var texture_path = equipped_item.spritePath
			
			var texture = load(texture_path)
			if texture:
				sprite.texture = texture
				sprite.hframes = equipped_item.spriteFrames.x if equipped_item.spriteFrames.x > 0 else 20
				sprite.vframes = equipped_item.spriteFrames.y if equipped_item.spriteFrames.y > 0 else 14
				sprite.frame = equipped_item.spriteFrame
				sprite.centered = false # Like inspiration system
				sprite.position = Vector2(4, 4) # Like inspiration system
				sprite.scale = Vector2(2.0, 2.0) # 2x size as requested
				ItemDatabase.apply_item_colors_to_sprite(sprite, equipped_item)
				button.add_child(sprite)
			
			# Add quantity label if item can have multiple (like arrows, bombs)
			var show_qty = equipped_item.can_have_multiple_of and (equipped_item.quantity > 1 or equipped_item.weapon_type == Item.WeaponType.BOMB)
			if show_qty:
				var quantity_label = Label.new()
				quantity_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT
				quantity_label.vertical_alignment = VERTICAL_ALIGNMENT_TOP
				quantity_label.size = Vector2(36, 36)
				quantity_label.custom_minimum_size = Vector2(36, 36)
				quantity_label.position = Vector2(0, 0)
				quantity_label.text = str(equipped_item.quantity)
				# Use dmg_numbers.png font (same as inventory items)
				var dmg_font_resource = load("res://assets/fonts/dmg_numbers.png")
				if dmg_font_resource:
					var font_file = FontFile.new()
					font_file.font_data = dmg_font_resource
					quantity_label.add_theme_font_override("font", font_file)
					quantity_label.add_theme_font_size_override("font_size", 16)
				quantity_label.add_theme_color_override("font_color", Color.GREEN)
				quantity_label.z_index = 100 # High z-index to show above item sprite
				quantity_label.z_as_relative = false # Absolute z-index
				button.add_child(quantity_label)
	
	# Update inventory grid - clear existing HBoxContainers
	for child in inventory_grid.get_children():
		child.queue_free()
	
	# Wait for old buttons to be fully freed before creating new ones
	await get_tree().process_frame
	
	# Add inventory items using HBoxContainers (like inspiration system)
	var current_hbox: HBoxContainer = null
	var items_per_row = 8 # Items per row (3 rows = 24 total items max)
	var items_in_current_row = 0
	
	for item in char_stats.inventory:
		# Create new HBoxContainer if needed
		if current_hbox == null or items_in_current_row >= items_per_row:
			current_hbox = HBoxContainer.new()
			current_hbox.add_theme_constant_override("separation", 0) # No separation like inspiration
			# Ensure HBoxContainer doesn't clip child buttons
			current_hbox.clip_contents = false
			inventory_grid.add_child(current_hbox)
			inventory_rows_list.append(current_hbox)
			items_in_current_row = 0
		
		# Create button with styleboxes (like inspiration system)
		var button = Button.new()
		# Button size increased to accommodate 1.5x scaled texture (24 * 1.5 = 36)
		button.custom_minimum_size = Vector2(36, 36) # Increased to fit 1.5x scaled texture
		button.size = Vector2(36, 36)
		if style_box_empty:
			button.add_theme_stylebox_override("normal", style_box_empty)
		if style_box_hover:
			button.add_theme_stylebox_override("hover", style_box_hover)
		if style_box_focused:
			button.add_theme_stylebox_override("focus", style_box_focused)
		if style_box_pressed:
			button.add_theme_stylebox_override("pressed", style_box_pressed)
		button.flat = false # Use styleboxes
		button.focus_mode = Control.FOCUS_ALL # Allow button to receive focus
		button.connect("pressed", _on_inventory_item_pressed.bind(item))
		button.connect("gui_input", _on_inventory_item_gui_input.bind(item))
		# Connect focus_entered like inspiration system (for keyboard navigation)
		# Note: focus_entered will trigger when we call grab_focus(), but _on_inventory_item_pressed
		# just updates selection state, so it should be safe
		button.connect("focus_entered", _on_inventory_item_pressed.bind(item))
		current_hbox.add_child(button)
		
		# Add item sprite (like inspiration system - positioned at 4,4 with centered=false)
		if item.spritePath != "":
			var sprite = Sprite2D.new()
			var texture = load(item.spritePath)
			if texture:
				sprite.texture = texture
				sprite.hframes = item.spriteFrames.x if item.spriteFrames.x > 0 else 20
				sprite.vframes = item.spriteFrames.y if item.spriteFrames.y > 0 else 14
				sprite.frame = item.spriteFrame
				sprite.centered = false # Like inspiration system
				sprite.position = Vector2(4, 4) # Like inspiration system
				sprite.scale = Vector2(2.0, 2.0) # 2x size as requested
				ItemDatabase.apply_item_colors_to_sprite(sprite, item)
				button.add_child(sprite)
		
		# Add quantity label if item quantity > 1 (show for all stacked items)
		if item.quantity > 1:
			var quantity_label = Label.new()
			quantity_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT
			quantity_label.vertical_alignment = VERTICAL_ALIGNMENT_TOP
			quantity_label.size = Vector2(36, 36)
			quantity_label.custom_minimum_size = Vector2(36, 36)
			quantity_label.position = Vector2(0, 0)
			quantity_label.text = str(item.quantity)
			# Use dmg_numbers.png font (same as damage_number.gd)
			var dmg_font_resource = load("res://assets/fonts/dmg_numbers.png")
			if dmg_font_resource:
				var font_file = FontFile.new()
				font_file.font_data = dmg_font_resource
				quantity_label.add_theme_font_override("font", font_file)
				quantity_label.add_theme_font_size_override("font_size", 16)
			quantity_label.add_theme_color_override("font_color", Color.GREEN)
			quantity_label.z_index = 100 # High z-index to show above item sprite
			button.add_child(quantity_label)
		
		inventory_buttons[item] = button
		inventory_items_list.append(item)
		items_in_current_row += 1
	
	# Clamp selection to valid range
	if inventory_selection_row >= inventory_rows_list.size():
		inventory_selection_row = max(0, inventory_rows_list.size() - 1)
	if inventory_selection_row >= 0 and inventory_selection_row < inventory_rows_list.size():
		var row = inventory_rows_list[inventory_selection_row]
		if inventory_selection_col >= row.get_child_count():
			inventory_selection_col = max(0, row.get_child_count() - 1)
	
	# Update selection only if selected_type is already set (don't auto-update during initialization)
	# Don't call _set_selection() here if we already have a valid selection - it will reset to 0,0
	# Only call it if selection is empty or invalid
	var should_reset_selection = false
	if selected_type == "":
		should_reset_selection = true
	elif selected_type == "item":
		# Check if current selection is still valid
		if inventory_selection_row < 0 or inventory_selection_row >= inventory_rows_list.size():
			should_reset_selection = true
		elif inventory_selection_row >= 0 and inventory_selection_row < inventory_rows_list.size():
			var row = inventory_rows_list[inventory_selection_row]
			if inventory_selection_col < 0 or inventory_selection_col >= row.get_child_count():
				should_reset_selection = true
	
	if should_reset_selection:
		_set_selection()
	elif selected_type != "":
		# Selection is valid, just update it
		_update_selection_from_navigation()
		_update_selection_rectangle()
		_update_info_panel()
	
	# Reset update flag
	is_updating_ui = false
	
func _set_selection():
	# NOW check for items AFTER UI is updated
	# Initialize selection - prefer inventory, but if empty, check equipment
	# Only set initial selection if not already set, or if current selection is invalid
	var needs_initial_selection = false
	if selected_type == "":
		needs_initial_selection = true
	elif selected_type == "item":
		# Check if current selection is still valid
		if inventory_selection_row >= inventory_rows_list.size() or inventory_selection_row < 0:
			needs_initial_selection = true
		elif inventory_selection_row >= 0 and inventory_selection_row < inventory_rows_list.size():
			var row = inventory_rows_list[inventory_selection_row]
			if inventory_selection_col >= row.get_child_count() or inventory_selection_col < 0:
				needs_initial_selection = true
	
	# Check if we have inventory items
	if inventory_rows_list.size() > 0 and inventory_items_list.size() > 0:
		if needs_initial_selection:
			# Only reset to 0 if we need initial selection
			selected_type = "item"
			inventory_selection_row = 0
			inventory_selection_col = 0
		# Ensure selection is set correctly (preserves existing selection if valid)
		_update_selection_from_navigation()
		# Debug: Print selection state
		print("InventoryUI: Selection - type: ", selected_type, " row: ", inventory_selection_row, " col: ", inventory_selection_col, " item: ", selected_item)
		# Now set focus - buttons should be ready
		await _update_selection_rectangle() # Await to ensure focus is set
		_update_info_panel()
	else:
		# No inventory items, try equipment
		var first_filled_slot = _find_next_filled_equipment_slot(-1, 1)
		if first_filled_slot >= 0:
			selected_type = "equipment"
			equipment_selection_index = first_filled_slot
			selected_slot = equipment_slots_list[first_filled_slot]
			# Ensure selection is set correctly
			_update_selection_from_navigation()
			# Debug: Print selection state
			print("InventoryUI: Initial selection - type: ", selected_type, " slot: ", selected_slot, " item: ", selected_item)
			# Now set focus - buttons should be ready
			await _update_selection_rectangle() # Await to ensure focus is set
			_update_info_panel()
		else:
			# Nothing to select (only print this AFTER UI is updated)
			selected_type = ""
			if selection_rectangle:
				selection_rectangle.visible = false
			if info_label:
				info_label.text = ""
			print("InventoryUI: No items to select")
	pass

func _update_selection_from_navigation():
	# Update selected_item/selected_slot based on navigation position
	# Early return if selected_type is not set yet (prevents errors during initialization)
	if selected_type == "":
		print("InventoryUI: _update_selection_from_navigation() - selected_type is empty, skipping")
		return
	
	print("InventoryUI: _update_selection_from_navigation() - selected_type: ", selected_type, " inventory_rows_list.size(): ", inventory_rows_list.size(), " inventory_items_list.size(): ", inventory_items_list.size())
	
	if selected_type == "equipment" and equipment_selection_index >= 0 and equipment_selection_index < equipment_slots_list.size():
		var slot_name = equipment_slots_list[equipment_selection_index]
		if _has_equipment_in_slot(slot_name):
			selected_slot = slot_name
			if local_player and local_player.character_stats:
				selected_item = local_player.character_stats.equipment[slot_name]
			else:
				selected_item = null
			print("InventoryUI: Selected equipment slot: ", slot_name, " item: ", selected_item)
		else:
			# Empty slot - switch to inventory
			selected_type = "item"
			selected_slot = ""
			selected_item = null
			if inventory_rows_list.size() > 0:
				inventory_selection_row = 0
				inventory_selection_col = 0
				_update_selection_from_navigation()
	elif selected_type == "item" and inventory_selection_row >= 0 and inventory_selection_row < inventory_rows_list.size():
		var row = inventory_rows_list[inventory_selection_row]
		print("InventoryUI: Checking item selection - row: ", inventory_selection_row, " col: ", inventory_selection_col, " row exists: ", row != null, " row child count: ", row.get_child_count() if row else 0)
		if row and inventory_selection_col >= 0 and inventory_selection_col < row.get_child_count():
			var items_per_row = 8  # Must match the items_per_row used when building rows
			var item_index = inventory_selection_row * items_per_row + inventory_selection_col
			print("InventoryUI: Calculated item_index: ", item_index, " inventory_items_list.size(): ", inventory_items_list.size())
			if item_index >= 0 and item_index < inventory_items_list.size():
				selected_item = inventory_items_list[item_index]
				selected_slot = ""
				print("InventoryUI: Selected inventory item: ", selected_item.item_name if selected_item else "null")
			else:
				selected_item = null
				selected_slot = ""
				print("InventoryUI: item_index out of range!")
		else:
			selected_item = null
			selected_slot = ""
			print("InventoryUI: Row or column invalid!")
	else:
		print("InventoryUI: selected_type invalid or row out of range!")

func _format_item_info(item: Item) -> String:
	# Format item description, stats modifiers, and controls
	var text = ""
	
	# Item name (always show)
	text += item.item_name
	
	# Description
	if item.description != "":
		text += "\n" + item.description
	
	text += "\n\n"
	
	# Stats modifiers
	var stat_lines = []
	if item.modifiers.has("str"):
		stat_lines.append("STR: +%d" % item.modifiers["str"])
	if item.modifiers.has("dex"):
		stat_lines.append("DEX: +%d" % item.modifiers["dex"])
	if item.modifiers.has("end"):
		stat_lines.append("END: +%d" % item.modifiers["end"])
	if item.modifiers.has("int"):
		stat_lines.append("INT: +%d" % item.modifiers["int"])
	if item.modifiers.has("wis"):
		stat_lines.append("WIS: +%d" % item.modifiers["wis"])
	if item.modifiers.has("lck"):
		stat_lines.append("LCK: +%d" % item.modifiers["lck"])
	if item.modifiers.has("dmg"):
		stat_lines.append("DMG: +%d" % item.modifiers["dmg"])
	if item.modifiers.has("def"):
		stat_lines.append("DEF: +%d" % item.modifiers["def"])
	if item.modifiers.has("hp"):
		stat_lines.append("HP: +%d" % item.modifiers["hp"])
	if item.modifiers.has("mp"):
		stat_lines.append("MP: +%d" % item.modifiers["mp"])
	if item.modifiers.has("maxhp"):
		stat_lines.append("MAXHP: +%d" % item.modifiers["maxhp"])
	if item.modifiers.has("maxmp"):
		stat_lines.append("MAXMP: +%d" % item.modifiers["maxmp"])
	
	if stat_lines.size() > 0:
		text += ", ".join(stat_lines)
		text += "\n\n"
	
	# Weight
	var item_weight = item.weight
	if item.can_have_multiple_of:
		item_weight *= item.quantity
	text += "Weight: %.1f" % item_weight
	text += "\n\n"
	
	# Controls
	if item.item_type == Item.ItemType.Equippable:
		if selected_type == "equipment":
			text += "Press F to unequip"
		else:
			text += "Press F to equip"
	elif item.item_type == Item.ItemType.Restoration:
		text += "Press F to consume"
	
	# Only show "Press E to drop" for inventory items, not equipment
	if selected_type == "item":
		text += ", Press E to drop"
	
	return text

func _update_info_panel():
	# Update info panel based on selected item
	if not info_label:
		print("InventoryUI: _update_info_panel() - info_label is null!")
		return
	
	print("InventoryUI: _update_info_panel() - selected_item: ", selected_item, " selected_type: ", selected_type)
	if selected_item:
		info_label.text = _format_item_info(selected_item)
		print("InventoryUI: Info panel text set: ", info_label.text.substr(0, 50) if info_label.text.length() > 50 else info_label.text)
	else:
		info_label.text = ""
		print("InventoryUI: Info panel text cleared (no selected_item)")

func _navigate_inventory(direction: String):
	# Handle navigation within inventory
	match direction:
		"left":
			if inventory_selection_col > 0:
				inventory_selection_col -= 1
			else:
				if inventory_selection_row > 0:
					inventory_selection_row -= 1
					var row = inventory_rows_list[inventory_selection_row]
					inventory_selection_col = row.get_child_count() - 1
				elif local_player and local_player.character_stats and local_player.character_stats.pending_level_up and local_player.character_stats.pending_stat_points > 0 and level_up_stat_buttons.size() > 0:
					selected_type = "level_up_stat"
					selected_level_up_stat_index = 0
					selected_slot = ""
					selected_item = null
					level_up_stat_buttons[0].call_deferred("grab_focus")
					if info_label and CharacterStats.LEVEL_UP_STAT_NAMES.size() > 0:
						var sn = CharacterStats.LEVEL_UP_STAT_NAMES[0]
						if sn in STAT_DESCRIPTIONS:
							info_label.text = STAT_DESCRIPTIONS[sn]
					_update_selection_rectangle()
					return
		"right":
			if inventory_selection_row < inventory_rows_list.size():
				var row = inventory_rows_list[inventory_selection_row]
				if inventory_selection_col < row.get_child_count() - 1:
					inventory_selection_col += 1
				else:
					# Wrap to start of next row
					if inventory_selection_row < inventory_rows_list.size() - 1:
						inventory_selection_row += 1
						inventory_selection_col = 0
		"up":
			if inventory_selection_row > 0:
				inventory_selection_row -= 1
				# Clamp column to valid range
				var row = inventory_rows_list[inventory_selection_row]
				if inventory_selection_col >= row.get_child_count():
					inventory_selection_col = row.get_child_count() - 1
			else:
				# Move to equipment slots (only if there are filled slots)
				var next_equip_index = _find_next_filled_equipment_slot(-1, 1) # Start from end, go forward
				if next_equip_index >= 0:
					selected_type = "equipment"
					equipment_selection_index = next_equip_index
					selected_slot = equipment_slots_list[next_equip_index]
					_update_selection_from_navigation()
					_update_selection_rectangle()
					_update_info_panel()
					return
		"down":
			if inventory_selection_row < inventory_rows_list.size() - 1:
				inventory_selection_row += 1
				# Clamp column to valid range
				var row = inventory_rows_list[inventory_selection_row]
				if inventory_selection_col >= row.get_child_count():
					inventory_selection_col = row.get_child_count() - 1
			# Can't go down from inventory (already at bottom)
	
	_update_selection_from_navigation()
	_update_selection_rectangle()
	_update_info_panel()

func _navigate_equipment(direction: String):
	# Handle navigation within equipment slots (only filled slots)
	# Equipment layout: 3 columns, 2 rows
	# Row 1: mainhand(0), offhand(1), headgear(2)
	# Row 2: armour(3), boots(4), accessory(5)
	match direction:
		"left":
			var next_index = _find_next_filled_equipment_slot(equipment_selection_index, -1)
			if next_index >= 0:
				equipment_selection_index = next_index
			elif local_player and local_player.character_stats and local_player.character_stats.pending_level_up and local_player.character_stats.pending_stat_points > 0 and level_up_stat_buttons.size() > 0:
				selected_type = "level_up_stat"
				selected_level_up_stat_index = 0
				selected_slot = ""
				selected_item = null
				level_up_stat_buttons[0].call_deferred("grab_focus")
				if info_label and CharacterStats.LEVEL_UP_STAT_NAMES.size() > 0:
					var sn = CharacterStats.LEVEL_UP_STAT_NAMES[0]
					if sn in STAT_DESCRIPTIONS:
						info_label.text = STAT_DESCRIPTIONS[sn]
				return
		"right":
			var next_index = _find_next_filled_equipment_slot(equipment_selection_index, 1)
			if next_index >= 0:
				equipment_selection_index = next_index
		"up":
			# Find next filled slot in row above (same column), or go to stats
			var current_row: int = floor(equipment_selection_index / 3.0)
			var current_col = equipment_selection_index % 3
			if current_row > 0:
				var target_index = (current_row - 1) * 3 + current_col
				var target_slot = equipment_slots_list[target_index]
				if _has_equipment_in_slot(target_slot):
					equipment_selection_index = target_index
				else:
					var next_index = _find_next_filled_equipment_slot(target_index - 1, 1)
					if next_index >= 0 and next_index < 3:
						equipment_selection_index = next_index
			elif local_player and local_player.character_stats and local_player.character_stats.pending_level_up and local_player.character_stats.pending_stat_points > 0 and level_up_stat_buttons.size() > 0:
				selected_type = "level_up_stat"
				selected_level_up_stat_index = 0
				selected_slot = ""
				selected_item = null
				level_up_stat_buttons[0].call_deferred("grab_focus")
				if info_label and CharacterStats.LEVEL_UP_STAT_NAMES.size() > 0:
					var sn = CharacterStats.LEVEL_UP_STAT_NAMES[0]
					if sn in STAT_DESCRIPTIONS:
						info_label.text = STAT_DESCRIPTIONS[sn]
				return
		"down":
			# Find next filled slot in row below (same column), or move to inventory
			var current_row: int = floor(equipment_selection_index / 3.0)
			var current_col = equipment_selection_index % 3
			if current_row < 1:
				var target_index = (current_row + 1) * 3 + current_col
				var target_slot = equipment_slots_list[target_index]
				if _has_equipment_in_slot(target_slot):
					equipment_selection_index = target_index
				else:
					# No filled slot below, move to inventory (only if inventory has items)
					if inventory_rows_list.size() > 0 and inventory_items_list.size() > 0:
						selected_type = "item"
						inventory_selection_row = 0
						inventory_selection_col = current_col
						# Clamp to valid range
						var inv_row = inventory_rows_list[0]
						if inventory_selection_col >= inv_row.get_child_count():
							inventory_selection_col = inv_row.get_child_count() - 1
						_update_selection_from_navigation()
						_update_selection_rectangle()
						_update_info_panel()
						return
					# No inventory items, stay on equipment
			else:
				# Already at bottom row, move to inventory (only if inventory has items)
				if inventory_rows_list.size() > 0 and inventory_items_list.size() > 0:
					selected_type = "item"
					inventory_selection_row = 0
					inventory_selection_col = current_col
					# Clamp to valid range
					var inv_row = inventory_rows_list[0]
					if inventory_selection_col >= inv_row.get_child_count():
						inventory_selection_col = inv_row.get_child_count() - 1
					_update_selection_from_navigation()
					_update_selection_rectangle()
					_update_info_panel()
					return
				# No inventory items, stay on equipment
	
	_update_selection_from_navigation()
	_update_selection_rectangle()
	_update_info_panel()

func _navigate_level_up_stats(direction: String) -> void:
	var n = level_up_stat_buttons.size()
	if n == 0:
		return
	match direction:
		"left":
			selected_level_up_stat_index = (selected_level_up_stat_index - 1 + n) % n
			level_up_stat_buttons[selected_level_up_stat_index].call_deferred("grab_focus")
			if info_label and selected_level_up_stat_index < CharacterStats.LEVEL_UP_STAT_NAMES.size():
				var sn = CharacterStats.LEVEL_UP_STAT_NAMES[selected_level_up_stat_index]
				if sn in STAT_DESCRIPTIONS:
					info_label.text = STAT_DESCRIPTIONS[sn]
		"right":
			if selected_level_up_stat_index >= n - 1:
				# Past last stat: go to equipment
				selected_type = "equipment"
				selected_level_up_stat_index = -1
				selected_slot = ""
				selected_item = null
				var next_index = _find_next_filled_equipment_slot(-1, 1)
				if next_index >= 0:
					equipment_selection_index = next_index
					selected_slot = equipment_slots_list[next_index]
					selected_item = local_player.character_stats.equipment[selected_slot] if local_player and local_player.character_stats else null
				_update_selection_from_navigation()
				_update_selection_rectangle()
				_update_info_panel()
				return
			selected_level_up_stat_index += 1
			level_up_stat_buttons[selected_level_up_stat_index].call_deferred("grab_focus")
			if info_label and selected_level_up_stat_index < CharacterStats.LEVEL_UP_STAT_NAMES.size():
				var sn = CharacterStats.LEVEL_UP_STAT_NAMES[selected_level_up_stat_index]
				if sn in STAT_DESCRIPTIONS:
					info_label.text = STAT_DESCRIPTIONS[sn]
		"up":
			pass
		"down":
			selected_type = "equipment"
			selected_level_up_stat_index = -1
			var next_index = _find_next_filled_equipment_slot(-1, 1)
			if next_index >= 0:
				equipment_selection_index = next_index
				selected_slot = equipment_slots_list[next_index]
				selected_item = local_player.character_stats.equipment[selected_slot] if local_player and local_player.character_stats else null
			_update_selection_from_navigation()
			_update_selection_rectangle()
			_update_info_panel()
			return
	# Don't call _update_info_panel - we've set stat description above

func _on_inventory_item_pressed(item: Item):
	if not local_player or not local_player.character_stats:
		return
	
	# Prevent updates during UI refresh (prevents infinite loops from focus_entered)
	if is_updating_ui:
		return
	
	selected_item = item
	selected_slot = ""
	selected_type = "item"
	
	# Update navigation position
	var item_index = inventory_items_list.find(item)
	if item_index >= 0:
		var items_per_row: int = 8
		inventory_selection_row = floor(item_index / float(items_per_row))
		inventory_selection_col = item_index % items_per_row
	
	_update_selection_highlight()
	_update_selection_rectangle()
	_update_info_panel()  # Show item description on single-click

func _on_inventory_item_gui_input(event: InputEvent, item: Item):
	# Handle double-click to equip/consume and right-click to drop
	if event is InputEventMouseButton:
		if event.button_index == MOUSE_BUTTON_LEFT and event.double_click and event.pressed:
			# Double-click detected - equip or consume the item
			selected_item = item
			selected_slot = ""
			selected_type = "item"
			
			# Update navigation position first
			var item_index = inventory_items_list.find(item)
			if item_index >= 0:
				var items_per_row: int = 8
				inventory_selection_row = floor(item_index / float(items_per_row))
				inventory_selection_col = item_index % items_per_row
			
			# Use the same logic as F key to equip/consume
			_handle_f_key()
		elif event.button_index == MOUSE_BUTTON_RIGHT and event.pressed:
			# Right-click detected - drop the item
			selected_item = item
			selected_slot = ""
			selected_type = "item"
			
			# Update navigation position first
			var item_index = inventory_items_list.find(item)
			if item_index >= 0:
				var items_per_row: int = 8
				inventory_selection_row = floor(item_index / float(items_per_row))
				inventory_selection_col = item_index % items_per_row
			
			# Use the same logic as E key to drop
			_handle_e_key()

func _on_mana_changed(new_mana: float, max_mana: float):
	# Update only MP bar and label when mana changes (don't rebuild entire UI)
	if mp_progress_bar and mp_value_label:
		mp_progress_bar.max_value = max(1.0, max_mana)
		mp_progress_bar.value = new_mana
		mp_value_label.text = str(int(new_mana)) + "/" + str(int(max_mana))

func _on_health_changed(new_hp: float, max_hp: float):
	# Update only HP bar and label when health changes (don't rebuild entire UI)
	if hp_progress_bar and hp_value_label:
		hp_progress_bar.max_value = max(1.0, max_hp)
		hp_progress_bar.value = new_hp
		hp_value_label.text = str(int(new_hp)) + "/" + str(int(max_hp))

func _on_character_changed(_char: CharacterStats):
	# Always update stats when character changes (even if inventory is closed)
	# Equipment changes affect max HP/MP which should be reflected everywhere
	_update_stats()
	
	# Only update UI if inventory is open (prevents unnecessary updates)
	if not is_open:
		return
	# Prevent recursive updates
	if is_updating_ui:
		return
	_update_ui()

func _input(event):
	# Toggle with Tab key
	if event is InputEventKey and event.keycode == KEY_TAB and event.pressed and not event.echo:
		if is_open:
			_close_inventory()
		else:
			_open_inventory()
		get_viewport().set_input_as_handled()
		return
	
	if not is_open:
		return
	
	# Arrow key navigation (use ui_left/right/up/down so keybindings work)
	var direction = ""
	var skip_repeat = event is InputEventKey and event.echo
	if not skip_repeat and event.is_action_pressed("ui_left"):
		direction = "left"
	elif not skip_repeat and event.is_action_pressed("ui_right"):
		direction = "right"
	elif not skip_repeat and event.is_action_pressed("ui_up"):
		direction = "up"
	elif not skip_repeat and event.is_action_pressed("ui_down"):
		direction = "down"
	if direction != "":
		if selected_type == "level_up_stat":
			_navigate_level_up_stats(direction)
		elif selected_type == "equipment":
			_navigate_equipment(direction)
		else:
			_navigate_inventory(direction)
		get_viewport().set_input_as_handled()
		return
	
	# F key: Unequip/equip items
	if event is InputEventKey and event.keycode == KEY_F and event.pressed and not event.echo:
		_handle_f_key()
		get_viewport().set_input_as_handled()
		return
	
	# E key: Drop selected item
	if event is InputEventKey and event.keycode == KEY_E and event.pressed and not event.echo:
		_handle_e_key()
		get_viewport().set_input_as_handled()
		return
	
	# Attack: Allocate level-up stat when a stat button is focused
	if event.is_action_pressed("attack") and not event.is_echo():
		var fc = get_viewport().gui_get_focus_owner()
		if level_up_stat_container and fc and is_instance_valid(level_up_stat_container) and fc.get_parent() == level_up_stat_container:
			var idx = level_up_stat_buttons.find(fc)
			if idx >= 0 and idx < CharacterStats.LEVEL_UP_STAT_NAMES.size():
				_on_level_up_stat_pressed(CharacterStats.LEVEL_UP_STAT_NAMES[idx])
				get_viewport().set_input_as_handled()
				return

func _handle_f_key():
	if not local_player or not local_player.character_stats:
		return
	if not _can_use_inventory():
		return
	
	var char_stats = local_player.character_stats
	
	if selected_type == "equipment" and selected_slot != "":
		var equipped_item = char_stats.equipment[selected_slot]
		if equipped_item:
			char_stats.unequip_item(equipped_item)
			# Play armour sound when unequipping
			if sfx_armour:
				sfx_armour.play()
			# After unequipping, if all equipment is empty, go to inventory
			var has_any_equipment = false
			for slot in equipment_slots_list:
				if _has_equipment_in_slot(slot):
					has_any_equipment = true
					break
			
			if not has_any_equipment:
				# No equipment left, go to inventory
				selected_type = "item"
				selected_slot = ""
				selected_item = null
				if inventory_rows_list.size() > 0:
					inventory_selection_row = 0
					inventory_selection_col = 0
				else:
					selected_type = ""
			else:
				# Find next filled equipment slot
				var next_index = _find_next_filled_equipment_slot(equipment_selection_index, 1)
				if next_index >= 0:
					equipment_selection_index = next_index
					selected_slot = equipment_slots_list[next_index]
					selected_item = char_stats.equipment[selected_slot]
				else:
					# No more equipment, go to inventory
					selected_type = "item"
					selected_slot = ""
					selected_item = null
					if inventory_rows_list.size() > 0:
						inventory_selection_row = 0
						inventory_selection_col = 0
			_update_selection_from_navigation()
			_update_selection_rectangle()
			return
	
	if selected_type == "item" and selected_item:
		if selected_item.item_type == Item.ItemType.Equippable and selected_item.equipment_type != Item.EquipmentType.NONE:
			# Remember which slot the item will be equipped to
			var target_slot_name = ""
			match selected_item.equipment_type:
				Item.EquipmentType.MAINHAND:
					target_slot_name = "mainhand"
				Item.EquipmentType.OFFHAND:
					target_slot_name = "offhand"
				Item.EquipmentType.HEADGEAR:
					target_slot_name = "headgear"
				Item.EquipmentType.ARMOUR:
					target_slot_name = "armour"
				Item.EquipmentType.BOOTS:
					target_slot_name = "boots"
				Item.EquipmentType.ACCESSORY:
					target_slot_name = "accessory"
			
			# Remember current item position before equipping
			var items_per_row = 8
			var current_item_index = inventory_selection_row * items_per_row + inventory_selection_col
			
			# Check if target slot has an item (will be placed back in inventory)
			var slot_has_item = char_stats.equipment[target_slot_name] != null
			
			# Check if this is the last item in inventory (before equipping)
			var was_last_item = char_stats.inventory.size() == 1
			
			# Equip the item, placing old item at the same position if slot had an item
			var insert_index = current_item_index if slot_has_item else -1
			char_stats.equip_item(selected_item, insert_index)
			
			# Play armour sound when equipping
			if sfx_armour:
				sfx_armour.play()
			
			# Update UI first
			_update_ui()
			
			# If slot had an item, keep selection at the same position (old item is now there)
			if slot_has_item and current_item_index < char_stats.inventory.size():
				# Keep selection at the same position
				selected_type = "item"
				selected_slot = ""
				# Recalculate row/col from index (may have changed if rows shifted)
				inventory_selection_row = floor(current_item_index / float(items_per_row))
				inventory_selection_col = current_item_index % items_per_row
				# Ensure row/col are within bounds
				if inventory_selection_row >= inventory_rows_list.size():
					inventory_selection_row = max(0, inventory_rows_list.size() - 1)
				if inventory_selection_row >= 0 and inventory_selection_row < inventory_rows_list.size():
					var row = inventory_rows_list[inventory_selection_row]
					if inventory_selection_col >= row.get_child_count():
						inventory_selection_col = max(0, row.get_child_count() - 1)
				_update_selection_from_navigation()
			elif was_last_item and target_slot_name != "":
				# Last item was equipped, move selection to equipment slot
				if target_slot_name in equipment_slots_list:
					selected_type = "equipment"
					selected_slot = target_slot_name
					equipment_selection_index = equipment_slots_list.find(target_slot_name)
					selected_item = char_stats.equipment[target_slot_name]
					_update_selection_from_navigation()
			else:
				# Item was removed, try to keep selection at same position if possible
				if current_item_index < char_stats.inventory.size():
					# Item at next position moved up, keep selection there
					selected_type = "item"
					selected_slot = ""
					inventory_selection_row = floor(current_item_index / float(items_per_row))
					inventory_selection_col = current_item_index % items_per_row
					if inventory_selection_row >= inventory_rows_list.size():
						inventory_selection_row = max(0, inventory_rows_list.size() - 1)
					if inventory_selection_row >= 0 and inventory_selection_row < inventory_rows_list.size():
						var row = inventory_rows_list[inventory_selection_row]
						if inventory_selection_col >= row.get_child_count():
							inventory_selection_col = max(0, row.get_child_count() - 1)
					_update_selection_from_navigation()
				elif current_item_index > 0:
					# Move to previous position (current_item_index - 1) if current is out of bounds
					var previous_index = current_item_index - 1
					inventory_selection_row = floor(previous_index / float(items_per_row))
					inventory_selection_col = previous_index % items_per_row
					if inventory_selection_row >= 0 and inventory_selection_row < inventory_rows_list.size():
						var row = inventory_rows_list[inventory_selection_row]
						if inventory_selection_col >= row.get_child_count():
							inventory_selection_col = max(0, row.get_child_count() - 1)
						selected_type = "item"
						selected_slot = ""
						_update_selection_from_navigation()
					else:
						# Previous position is also out of bounds, move to equipment if available
						selected_type = ""
						selected_slot = ""
						selected_item = null
						_update_selection_from_navigation()
				else:
					# No items left, move to equipment if available
					selected_type = ""
					selected_slot = ""
					selected_item = null
					_update_selection_from_navigation()
			
			# Update selection rectangle and info panel
			_update_selection_rectangle()
			_update_info_panel()
		elif selected_item.item_type == Item.ItemType.Restoration:
			_use_consumable_item(selected_item)
			_update_info_panel()

func _use_consumable_item(item: Item):
	if not local_player or not local_player.character_stats:
		return
	if not _can_use_inventory():
		return
	
	var char_stats = local_player.character_stats
	
	# Remember current item position before consuming
	var items_per_row = 8
	var current_item_index = inventory_selection_row * items_per_row + inventory_selection_col
	
	# Determine if it's a potion or food based on item name
	var is_potion = "potion" in item.item_name.to_lower()
	
	# Play appropriate sound
	if is_potion:
		if sfx_potion:
			sfx_potion.play()
	else:
		# Food item
		if sfx_food:
			sfx_food.play()
	
	if item.modifiers.has("hp"):
		var hp_heal = item.modifiers["hp"]
		if local_player.has_method("heal"):
			local_player.heal(hp_heal)
	if item.modifiers.has("mp"):
		var mana_amount = item.modifiers["mp"]
		char_stats.restore_mana(mana_amount)
	
	var index = char_stats.inventory.find(item)
	if index >= 0:
		char_stats.inventory.remove_at(index)
		char_stats.character_changed.emit(char_stats)
		
		# Update UI first
		_update_ui()
		
		# Try to keep selection at the same position if possible
		if current_item_index < char_stats.inventory.size():
			# Item at next position moved up, keep selection there
			selected_type = "item"
			selected_slot = ""
			inventory_selection_row = floor(current_item_index / float(items_per_row))
			inventory_selection_col = current_item_index % items_per_row
			if inventory_selection_row >= inventory_rows_list.size():
				inventory_selection_row = max(0, inventory_rows_list.size() - 1)
			if inventory_selection_row >= 0 and inventory_selection_row < inventory_rows_list.size():
				var row = inventory_rows_list[inventory_selection_row]
				if inventory_selection_col >= row.get_child_count():
					inventory_selection_col = max(0, row.get_child_count() - 1)
				_update_selection_from_navigation()
				_update_selection_rectangle()
		elif current_item_index > 0:
			# Move to previous position if current is out of bounds
			current_item_index = char_stats.inventory.size() - 1
			inventory_selection_row = floor(current_item_index / float(items_per_row))
			inventory_selection_col = current_item_index % items_per_row
			if inventory_selection_row >= 0 and inventory_selection_row < inventory_rows_list.size():
				var row = inventory_rows_list[inventory_selection_row]
				if inventory_selection_col >= row.get_child_count():
					inventory_selection_col = max(0, row.get_child_count() - 1)
				_update_selection_from_navigation()
				_update_selection_rectangle()
		else:
			# No items left, clear selection
			selected_type = ""
			selected_slot = ""
			selected_item = null
			_update_selection_from_navigation()
			_update_selection_rectangle()
	
	print(local_player.name, " used item: ", item.item_name)

func _handle_e_key():
	if not local_player or not local_player.character_stats:
		return
	if not _can_use_inventory():
		return
	
	if selected_type != "item" or not selected_item:
		return
	
	var char_stats = local_player.character_stats
	
	# Play armour sound when dropping equipment
	if selected_item.item_type == Item.ItemType.Equippable:
		if sfx_armour:
			sfx_armour.play()
	
	if not selected_item in char_stats.inventory:
		return
	
	var index = char_stats.inventory.find(selected_item)
	if index >= 0:
		char_stats.inventory.remove_at(index)
	
	var drop_position = local_player.global_position + Vector2(randf_range(-20, 20), randf_range(-20, 20))
	var game_world = get_tree().get_first_node_in_group("game_world")
	var entities_node = null
	if game_world:
		entities_node = game_world.get_node_or_null("Entities")
	
	# In multiplayer, clients need to request server to spawn loot
	if multiplayer.has_multiplayer_peer() and not multiplayer.is_server():
		# Client: send drop request to server
		if game_world and game_world.has_method("_request_item_drop"):
			game_world._request_item_drop.rpc_id(1, selected_item.save(), drop_position, local_player.get_multiplayer_authority())
		else:
			# Fallback: try to spawn locally (won't sync)
			if entities_node:
				var loot = ItemLootHelper.spawn_item_loot(selected_item, drop_position, entities_node, game_world)
				if loot and local_player.has_method("get_multiplayer_authority"):
					var player_peer_id = local_player.get_multiplayer_authority()
					loot.set_meta("dropped_by_peer_id", player_peer_id)
					loot.set_meta("drop_time", Time.get_ticks_msec())
	else:
		# Server or single-player: spawn directly
		if entities_node:
			var loot = ItemLootHelper.spawn_item_loot(selected_item, drop_position, entities_node, game_world)
			if loot and local_player.has_method("get_multiplayer_authority"):
				var player_peer_id = local_player.get_multiplayer_authority()
				loot.set_meta("dropped_by_peer_id", player_peer_id)
				loot.set_meta("drop_time", Time.get_ticks_msec())
	
	selected_item = null
	selected_slot = ""
	selected_type = ""
	
	char_stats.character_changed.emit(char_stats)
	
	print(local_player.name, " dropped item")

func _open_inventory():
	if is_open:
		return
	
	# Workaround: On first open, immediately close and reopen to ensure proper initialization
	if is_first_open:
		is_first_open = false
		is_open = true
		if container:
			container.visible = true
		_lock_player_controls(true)
		_update_ui()
		# Wait a frame
		await get_tree().process_frame
		# Close immediately
		_close_inventory()
		# Wait a frame
		await get_tree().process_frame
		# Now reopen properly (will continue with normal flow below)
	
	is_open = true
	if container:
		container.visible = true
	
	_lock_player_controls(true)
	
	# Reset selection state BEFORE updating UI (so _update_ui doesn't try to update selection)
	selected_type = ""
	selected_item = null
	selected_slot = ""
	
	_update_ui()
	_update_stats()
	
	if not local_player:
		_find_local_player()

func _close_inventory():
	if not is_open:
		return
	
	is_open = false
	if container:
		container.visible = false
	
	if selection_rectangle:
		selection_rectangle.visible = false
	
	selected_item = null
	selected_slot = ""
	selected_type = ""
	
	_lock_player_controls(false)

func _lock_player_controls(lock: bool):
	var game_world = get_tree().get_first_node_in_group("game_world")
	if game_world:
		var player_manager = game_world.get_node_or_null("PlayerManager")
		if player_manager:
			var local_players = player_manager.get_local_players()
			for player in local_players:
				player.controls_disabled = lock
