class_name StockpileZone extends StorageDestination
## Concrete floor stockpile zone. A rectangular region (in tile coords) that
## accepts items matching the filter and deposits them one-per-tile.
##
## Rendered as a translucent priority-tinted overlay via _draw(). The overlay
## is always visible — Phase 17 will toggle it when the Zones panel is open.
## z_index = -1 keeps the tint below items (z_index 0) and pawns.
##
## Register/unregister with World.stockpiles happen automatically in
## _ready / _exit_tree — no external wiring needed.
##
## One-stack-per-tile, one-type-per-tile rule (design.md).
##
## See docs/architecture.md "StockpileZone".

## Region in tile coordinates. (0,0) relative to this node's map position;
## in practice this node lives at world origin so region is in world-tile space.
@export var region: Rect2i = Rect2i(0, 0, 4, 4)

## Player-visible label shown in zone inspect UI (Phase 17).
@export var label: String = "Stockpile"

## Pixel size of one tile — must match World.TILE_SIZE_PX.
const _TILE_PX: int = 16

## Priority-keyed fill colors for the overlay (Color(r, g, b, a)).
const _PRIORITY_COLORS: Dictionary = {
	StorageDestination.Priority.CRITICAL: Color(0.9, 0.3, 0.3, 0.15),
	StorageDestination.Priority.HIGH:     Color(0.9, 0.6, 0.3, 0.15),
	StorageDestination.Priority.NORMAL:   Color(0.9, 0.9, 0.3, 0.12),
	StorageDestination.Priority.LOW:      Color(0.3, 0.9, 0.3, 0.10),
	StorageDestination.Priority.OFF:      Color(0.3, 0.3, 0.3, 0.10),
}


func _ready() -> void:
	z_index = -1
	World.register_stockpile(self)
	queue_redraw()


func _exit_tree() -> void:
	World.unregister_stockpile(self)


# ── StorageDestination overrides ─────────────────────────────────────────────

func accepts(item) -> bool:
	return _filter_accepts(item)


func covers_tile(tile: Vector2i) -> bool:
	return region.has_point(tile)


## Scan region cells in row-major order; return the first tile not occupied by
## an item that is not being carried. Returns Vector2i(-1, -1) if the zone is
## full or the item fails the filter.
func find_drop_position(item) -> Vector2i:
	if not accepts(item):
		return Vector2i(-1, -1)
	for x in range(region.position.x, region.position.x + region.size.x):
		for y in range(region.position.y, region.position.y + region.size.y):
			var cell := Vector2i(x, y)
			if _is_cell_free(cell):
				return cell
	return Vector2i(-1, -1)


# ── drawing ───────────────────────────────────────────────────────────────────

func _draw() -> void:
	var fill_color: Color = _PRIORITY_COLORS.get(priority, Color(0.5, 0.5, 0.5, 0.12))
	var border_color := Color(fill_color.r, fill_color.g, fill_color.b, 0.6)
	var tile_px := float(_TILE_PX)

	# Filled rectangle covering the entire region.
	var rect_px := Rect2(
		Vector2(region.position) * tile_px,
		Vector2(region.size) * tile_px
	)
	draw_rect(rect_px, fill_color, true)

	# 1-px border outline.
	draw_rect(rect_px, border_color, false, 1.0)


# ── save / load ───────────────────────────────────────────────────────────────

func to_dict() -> Dictionary:
	return {
		"class_id": &"stockpile_zone",
		"region_x": region.position.x,
		"region_y": region.position.y,
		"region_w": region.size.x,
		"region_h": region.size.y,
		"priority": int(priority),
		"label": label,
		"accepted_types": accepted_types.map(func(t): return String(t)),
	}


func from_dict(d: Dictionary) -> void:
	region = Rect2i(
		int(d.get("region_x", 0)),
		int(d.get("region_y", 0)),
		int(d.get("region_w", 4)),
		int(d.get("region_h", 4))
	)
	priority = d.get("priority", StorageDestination.Priority.NORMAL) as StorageDestination.Priority
	label = str(d.get("label", "Stockpile"))
	var raw_types: Array = d.get("accepted_types", [])
	accepted_types.clear()
	for s in raw_types:
		accepted_types.append(StringName(s))
	queue_redraw()


# ── internal helpers ──────────────────────────────────────────────────────────

## Returns true when no un-carried item is sitting on `cell`.
## One-stack-per-tile rule: the first occupied, non-carried item blocks the cell.
func _is_cell_free(cell: Vector2i) -> bool:
	for it in World.items:
		if it.tile == cell and not it.being_carried:
			return false
	return true
