## RoomChest — tappable storage node. Spawns HoldableItem/OutfitItem instances on demand.
## Items fly out with a tween. Receives items back via receive_item().
class_name RoomChest extends Node2D

signal items_spawned(chest: RoomChest)
signal item_received(chest: RoomChest, item_id: String)

const SPAWN_TWEEN_DURATION: float = 0.3

@export var chest_id: String = ""
@export var tap_radius: float = 50.0

var _spawned_items: Array[HoldableItem] = []
var _item_configs: Array[ChestItemData] = []


func _ready() -> void:
	add_to_group("room_chests")
	_item_configs = RoomChestConfig.get_items(chest_id)
	if not chest_id.is_empty() and GameState.has_method("get_chest_state"):
		if not GameState.get_chest_state(chest_id).is_empty():
			call_deferred("spawn_items")


func _unhandled_input(event: InputEvent) -> void:
	var press_pos: Vector2 = _get_press_position(event)
	if press_pos == Vector2.INF:
		return
	var canvas_pos: Vector2 = get_viewport().get_canvas_transform().affine_inverse() * press_pos
	if canvas_pos.distance_to(global_position) > tap_radius:
		return
	get_viewport().set_input_as_handled()
	AudioManager.play_sfx("chest_tap")
	spawn_items()


func spawn_items() -> void:
	if not _spawned_items.is_empty():
		return
	AudioManager.play_sfx("item_spawn")
	var parent: Node = get_parent()
	for config: ChestItemData in _item_configs:
		var item: HoldableItem = _create_item(config)
		item.home_chest = self
		if parent != null:
			parent.add_child(item)
		else:
			add_child(item)
		item.global_position = global_position
		_spawned_items.append(item)
		_tween_item_out(item, config.spawn_offset)
	if GameState.has_method("set_chest_state"):
		GameState.set_chest_state(chest_id, _get_spawned_ids())
	items_spawned.emit(self)


func receive_item(item: HoldableItem) -> void:
	if not _spawned_items.has(item):
		return
	_spawned_items.erase(item)
	if GameState.has_method("set_chest_state"):
		if _spawned_items.is_empty():
			GameState.clear_chest_state(chest_id)
		else:
			GameState.set_chest_state(chest_id, _get_spawned_ids())
	item_received.emit(self, item.item_id)
	_tween_item_in(item)


func are_items_spawned() -> bool:
	return not _spawned_items.is_empty()


func get_spawned_count() -> int:
	return _spawned_items.size()


func get_item_config_count() -> int:
	return _item_configs.size()


func get_spawned_item(index: int) -> HoldableItem:
	if index < 0 or index >= _spawned_items.size():
		return null
	return _spawned_items[index]


func _get_press_position(event: InputEvent) -> Vector2:
	if event is InputEventScreenTouch and event.pressed:
		return event.position
	if event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT:
		return event.position
	return Vector2.INF


func _create_item(config: ChestItemData) -> HoldableItem:
	var item: HoldableItem
	if config.item_type == ChestItemData.ItemType.OUTFIT:
		var outfit: OutfitItem = OutfitItem.new()
		outfit.outfit_layer = config.outfit_layer
		item = outfit
	else:
		item = HoldableItem.new()
	item.item_id = config.item_id
	return item


func _get_spawned_ids() -> Array[String]:
	var ids: Array[String] = []
	for item: HoldableItem in _spawned_items:
		ids.append(item.item_id)
	return ids


func _tween_item_out(item: HoldableItem, offset: Vector2) -> void:
	var tween: Tween = create_tween()
	tween.tween_property(item, "global_position", global_position + offset, SPAWN_TWEEN_DURATION)


func _tween_item_in(item: HoldableItem) -> void:
	var tween: Tween = create_tween()
	tween.tween_property(item, "global_position", global_position, SPAWN_TWEEN_DURATION)
	tween.tween_callback(item.queue_free)
