class_name ActionSelectionSystem
extends RefCounted


func select_action(npc: SimNPC, village: SimVillage) -> ActionSelectionResult:
	if npc.is_dead:
		return null
	if npc.is_starving:
		if npc.get_inventory_amount(SimulationIds.RESOURCE_FOOD) >= 1.0:
			return ActionSelectionResult.new(SimulationIds.ACTION_EAT, 1.0)
		if village.food > 0:
			return ActionSelectionResult.new(SimulationIds.ACTION_WITHDRAW_FOOD, 1.0)
		return ActionSelectionResult.new(SimulationIds.ACTION_GATHER_FOOD, 4.0)
	if npc.hunger > 75.0:
		if npc.get_inventory_amount(SimulationIds.RESOURCE_FOOD) >= 1.0:
			return ActionSelectionResult.new(SimulationIds.ACTION_EAT)
		if village.food > 0:
			return ActionSelectionResult.new(SimulationIds.ACTION_WITHDRAW_FOOD)
		return ActionSelectionResult.new(SimulationIds.ACTION_GATHER_FOOD)
	if npc.get_inventory_amount(SimulationIds.RESOURCE_FOOD) > 0.0:
		return ActionSelectionResult.new(SimulationIds.ACTION_DEPOSIT_FOOD)
	if npc.energy < 25.0:
		return ActionSelectionResult.new(SimulationIds.ACTION_REST)
	return ActionSelectionResult.new(_choose_best_work_action(npc, village))


func _choose_best_work_action(npc: SimNPC, village: SimVillage) -> StringName:
	var scores := {
		SimulationIds.ACTION_GATHER_FOOD:
		_calculate_score(
			npc,
			SimulationIds.ACTION_GATHER_FOOD,
			village.food_priority,
			village.food,
			15.0,
			30.0,
			3.0,
			1.5
		),
		SimulationIds.ACTION_GATHER_WOOD:
		_calculate_score(
			npc,
			SimulationIds.ACTION_GATHER_WOOD,
			village.wood_priority,
			village.wood,
			10.0,
			20.0,
			2.5,
			1.0
		),
		SimulationIds.ACTION_PATROL:
		_calculate_score(
			npc,
			SimulationIds.ACTION_PATROL,
			village.safety_priority,
			village.safety,
			30.0,
			50.0,
			3.0,
			1.5
		),
		SimulationIds.ACTION_STUDY:
		_calculate_score(
			npc,
			SimulationIds.ACTION_STUDY,
			village.knowledge_priority,
			village.knowledge,
			10.0,
			25.0,
			1.5,
			0.75
		)
	}
	var best_action := SimulationIds.ACTION_GATHER_FOOD
	var best_score: float = scores[best_action]
	for action_id in [
		SimulationIds.ACTION_GATHER_WOOD, SimulationIds.ACTION_PATROL, SimulationIds.ACTION_STUDY
	]:
		var score: float = scores[action_id]
		if score > best_score:
			best_action = action_id
			best_score = score
	return best_action


func _calculate_score(
	npc: SimNPC,
	action_id: StringName,
	base_priority: float,
	resource_amount: float,
	critical_threshold: float,
	low_threshold: float,
	critical_bonus: float,
	low_bonus: float
) -> float:
	var score := base_priority
	if resource_amount < critical_threshold:
		score += critical_bonus
	elif resource_amount < low_threshold:
		score += low_bonus
	var definition := SimulationDefinitions.get_action(action_id)
	if (
		definition != null
		and not definition.preferred_profession_id.is_empty()
		and npc.profession == definition.preferred_profession_id
	):
		score += 2.0
	if action_id == npc.last_task:
		score -= 1.5
	score += npc.random_source.randf_range(0.0, 0.5)
	if npc.debug_logs:
		print("[ActionSelection] ", npc.npc_name, " score ", action_id, " = ", score)
	return score
