class_name CleaningProvider extends WorkProvider
## Phase 13 — WorkProvider for the Cleaning work category.
##
## Priority 2: fires when there is nothing more productive to do
## (below hauling=3, above rest=0).
##
## make_job / find_best_for logic:
##   Scan DirtinessSystem.dirt_map for tiles with dirt >= DIRTY_THRESHOLD.
##   Pick the nearest to the pawn by Manhattan distance.
##   Build a 2-toil job: walk_to(tile) → kind_clean(tile).
##
## There is no Cleaning skill yet (Phase 17+ skill matrix).  The clean toil
## takes a flat CLEAN_TICKS sim ticks to reduce dirt from any level to 0.
##
## JobRunner._tick_clean reduces DirtinessSystem.dirt_at(tile) by
## DIRT_REDUCTION_PER_TICK each sim tick until dirt <= 0.
##
## Audit.log fires on job start and on toil completion (via JobRunner).

## Base number of sim ticks to clean a tile from any level to 0.
## No skill modifier for now; Phase 17 wires skill × speed.
const CLEAN_TICKS: int = 40


func _init() -> void:
	category = &"clean"
	priority = 2


# ── WorkProvider override ─────────────────────────────────────────────────────

## Returns a cleaning Job for `pawn`, or null if no dirty tiles exist.
## Picks the tile closest to `pawn` (Manhattan distance) with dirt >= DIRTY_THRESHOLD.
func find_best_for(pawn) -> Job:
	# Safety — dirtiness system may not be wired yet (Agent A rooms arrive slightly later).
	if World.get("dirtiness_system") == null:
		return null

	var ds = World.dirtiness_system
	if ds == null:
		return null

	var best_tile: Vector2i = Vector2i(-1, -1)
	var best_dist: int = 999999

	for tile in ds.dirt_map.keys():
		var dirt_val: float = float(ds.dirt_map[tile])
		if dirt_val < DirtinessSystem.DIRT_DIRTY_THRESHOLD:
			continue
		# target_node stores the Vector2i tile coordinate (field is untyped — accepts
		# non-Node values). Dirty tiles have no scene Node; the tile position itself
		# is the unique claim key.
		if Job.is_target_taken_by_other(tile, pawn):
			continue
		var d: int = abs(tile.x - pawn.tile.x) + abs(tile.y - pawn.tile.y)
		if d < best_dist:
			best_dist = d
			best_tile = tile

	if best_tile == Vector2i(-1, -1):
		return null

	var j := Job.new()
	j.label = "Clean (%d,%d)" % [best_tile.x, best_tile.y]
	j.target_node = best_tile
	j.toils.append(Toil.walk_to(best_tile))
	j.toils.append(Toil.clean_at(best_tile))
	return j
