class_name GraveyardZone extends StorageDestination
## Phase 14 — Graveyard floor zone.  Accepts corpses only.
##
## Structurally identical to StockpileZone but locked to Item.TYPE_CORPSE.
## The `accepts()` override adds a Corpse type-check so Items of type &"corpse"
## that are NOT Corpse entities never match (belt-and-suspenders).
##
## Visual: darker brownish overlay (brown-grey to read as turned earth) vs the
## yellow-tinted StockpileZone overlay.
##
## One slot per tile — corpses are large; one per cell mirrors design.md.
##
## Register/unregister with World.stockpiles happen automatically in
## _ready / _exit_tree — no external wiring needed.
##
## See docs/implementation.md Phase 14 "GraveyardZone".

## Region in tile coordinates.
@export var region: Rect2i = Rect2i(0, 0, 4, 4)

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

const _TILE_PX: int = 16

## Earthen-brown fill at two priority extremes — graveyard zones are fixed
## priority NORMAL; other Priority values are valid but unlikely to be set by
## the player in Phase 14. Tint distinguishes from StockpileZone yellow.
const _FILL_COLOR: Color = Color(0.40, 0.28, 0.18, 0.18)   # dark earth brown
const _BORDER_COLOR: Color = Color(0.30, 0.20, 0.12, 0.55)  # deeper border


func _ready() -> void:
	z_index = -1
	accepted_types = [Item.TYPE_CORPSE]
	World.register_stockpile(self)
	queue_redraw()


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


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

func accepts(item) -> bool:
	if priority == StorageDestination.Priority.OFF:
		return false
	# Must be type corpse AND an actual Corpse entity (not a regular Item).
	if not item.has_method("get_item_type"):
		return false
	if item.get_item_type() != Item.TYPE_CORPSE:
		return false
	# Only accept if there is a dug GraveSlot at an open tile in our region.
	return _find_open_grave_slot() != null


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


## Scan region for an open dug GraveSlot. Returns the slot or null.
## "Open" means the slot is in DUG state (not yet occupied / being hauled to).
func find_drop_position(item) -> Vector2i:
	if not accepts(item):
		return Vector2i(-1, -1)
	var slot = _find_open_grave_slot()
	if slot == null:
		return Vector2i(-1, -1)
	return slot.tile


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

func _draw() -> void:
	var tile_px := float(_TILE_PX)
	var rect_px := Rect2(
		Vector2(region.position) * tile_px,
		Vector2(region.size) * tile_px
	)
	draw_rect(rect_px, _FILL_COLOR, true)
	draw_rect(rect_px, _BORDER_COLOR, false, 1.0)

	# Small cross marker in the top-left corner of the zone as a visual cue.
	var cross_center := Vector2(region.position) * tile_px + Vector2(tile_px * 0.5, tile_px * 0.5)
	var cross_color := Color(_BORDER_COLOR.r, _BORDER_COLOR.g, _BORDER_COLOR.b, 0.70)
	draw_line(cross_center + Vector2(0.0, -4.0), cross_center + Vector2(0.0, 4.0), cross_color, 1.5)
	draw_line(cross_center + Vector2(-3.0, -1.5), cross_center + Vector2(3.0, -1.5), cross_color, 1.5)


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

func to_dict() -> Dictionary:
	return {
		"class_id": &"graveyard_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,
	}


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", "Graveyard"))
	queue_redraw()


# ── internal ─────────────────────────────────────────────────────────────────

## Returns the first GraveSlot within the region that is in DUG state and not
## already being hauled to. Returns null if none found.
func _find_open_grave_slot():
	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)
			# Look for a GraveSlot in World.stockpiles that covers this cell
			# and is in DUG state.
			for dest in World.stockpiles:
				if dest == self:
					continue
				if not dest.has_method("is_grave_slot_dug"):
					continue
				if dest.covers_tile(cell) and dest.is_grave_slot_dug():
					return dest
	return null
