class_name StorageDestination extends Node2D
## Abstract base for all item-storage destinations (floor stockpile zones,
## containers, etc.). Hauling AI treats all subclasses as a unified candidate
## pool via this interface.
##
## StorageDestination extends Node2D (not Node) so subclasses can implement
## _draw() for priority-tinted overlays without a separate CanvasItem child.
##
## Subclasses MUST override: accepts(), find_drop_position(), covers_tile().
## Subclasses SHOULD call World.register_stockpile(self) in _ready() and
## World.unregister_stockpile(self) in _exit_tree().
##
## See docs/architecture.md "Storage destinations: a unified concept".

## Five priority levels matching Rimworld semantics (design.md Priorities).
## Lower enum int = higher priority (CRITICAL = 0 pulls before LOW = 4).
## Priority.OFF = no hauling in or out; invisible to HaulingProvider.
enum Priority {
	CRITICAL = 0,
	HIGH     = 1,
	NORMAL   = 2,
	LOW      = 3,
	OFF      = 4,
}

## Priority determines whether haulers will fill this destination and whether
## items here will be re-hauled upward to a higher-priority destination.
@export var priority: Priority = Priority.NORMAL

## Item types this destination accepts. Empty array = wildcard (accepts all).
## Each entry is a StringName matching Item.TYPE_* constants (e.g. &"wood").
@export var accepted_types: Array[StringName] = []

## Emitted when items are registered or unregistered with this destination,
## so interested parties (UI, re-scan logic) can react without polling.
signal contents_changed


# ── abstract interface — subclasses must override ────────────────────────────

## Returns true if this destination currently accepts `item` (filter + priority
## check + any capacity logic owned by the subclass).
func accepts(item) -> bool:
	push_error("StorageDestination.accepts: '%s' must override this method" % name)
	return false


## Returns a tile coordinate inside this destination where `item` can be
## placed (filter-pass AND the tile is not already occupied by another item).
## Returns Vector2i(-1, -1) when no slot is available.
func find_drop_position(item) -> Vector2i:
	push_error("StorageDestination.find_drop_position: '%s' must override this method" % name)
	return Vector2i(-1, -1)


## Returns true if `tile` falls inside this destination's region.
## Used by HaulingProvider to find which destination currently holds an item.
func covers_tile(tile: Vector2i) -> bool:
	push_error("StorageDestination.covers_tile: '%s' must override this method" % name)
	return false


# ── shared helper ────────────────────────────────────────────────────────────

## Priority-and-filter gate, shared by all subclasses.
## Returns false when OFF or when the item's type is not in accepted_types.
## accepted_types.is_empty() is the wildcard "accept any type" case.
## Resolves item_type defensively — Corpse entities expose get_item_type()
## rather than a plain .item_type property; both are handled here.
func _filter_accepts(item) -> bool:
	if priority == Priority.OFF:
		return false
	if accepted_types.is_empty():
		return true
	# Resolve the type string defensively: prefer .item_type property, fall back
	# to get_item_type() for Corpse entities (Phase 14).
	var type: StringName
	var t = item.get("item_type")
	if t != null:
		type = t
	elif item.has_method("get_item_type"):
		type = item.get_item_type()
	else:
		return false
	return type in accepted_types
