class_name SimNPC
extends RefCounted

const TASK_STATE_IDLE := &"idle"
const TASK_STATE_TRAVELING := &"traveling"
const TASK_STATE_WORKING := &"working"
const TASK_STATE_COMPLETE := &"complete"

var id: int
var npc_name: String
var profession: StringName
var hunger: float
var energy: float
var strength: float
var intelligence: float
var current_task: StringName = SimulationIds.ACTION_IDLE
var task_state: StringName = TASK_STATE_IDLE
var position: Vector3

var is_starving := false
var starvation_ticks := 0
var starvation_death_threshold := 20
var is_dead := false

var task_duration := 0.0
var task_progress := 0.0
var task_complete := true
var target_id: StringName = &""
var travel_target_position: Vector3
var has_travel_target := false
var inventory: Dictionary = {}
var last_task: StringName
var random_source: RandomNumberGenerator
var debug_logs := true


func _init(
	_id: int,
	_npc_name: String,
	_profession: StringName,
	_strength: float,
	_intelligence: float,
	_random_source: RandomNumberGenerator = null
) -> void:
	id = _id
	npc_name = _npc_name
	profession = _profession
	strength = _strength
	intelligence = _intelligence
	random_source = _random_source
	if random_source == null:
		random_source = RandomNumberGenerator.new()
		random_source.seed = id + 1
	hunger = random_source.randf_range(20.0, 80.0)
	energy = random_source.randf_range(40.0, 100.0)
	position = Vector3(
		random_source.randf_range(-8.0, 8.0), 0.0, random_source.randf_range(-8.0, 8.0)
	)


func die_from_starvation() -> void:
	is_dead = true
	current_task = SimulationIds.ACTION_DEAD
	task_state = TASK_STATE_IDLE
	task_progress = 0.0
	task_duration = 0.0
	task_complete = true
	has_travel_target = false

	if debug_logs:
		print("[SimNPC] ", npc_name, " died from starvation.")


func get_inventory_amount(item_id: StringName) -> float:
	return float(inventory.get(String(item_id), 0.0))


func add_inventory(item_id: StringName, amount: float) -> void:
	inventory[String(item_id)] = get_inventory_amount(item_id) + maxf(amount, 0.0)


func remove_inventory(item_id: StringName, requested_amount: float) -> float:
	var removed := minf(maxf(requested_amount, 0.0), get_inventory_amount(item_id))
	inventory[String(item_id)] = get_inventory_amount(item_id) - removed
	return removed


func set_task(action_id: StringName, duration: float = -1.0) -> void:
	var definition := SimulationDefinitions.get_action(action_id)
	if definition == null:
		push_error("SimNPC: unknown action_id '%s'" % action_id)
		return
	current_task = action_id
	task_duration = (duration if duration >= 0.0 else definition.default_duration)
	task_progress = 0.0
	task_complete = false
	task_state = TASK_STATE_TRAVELING
	has_travel_target = false


func start_working() -> void:
	if task_state != TASK_STATE_TRAVELING:
		return

	task_state = TASK_STATE_WORKING
	task_progress = 0.0
	task_complete = false
