class_name NPCStateRecord
extends RefCounted

const SCHEMA_VERSION := 1

var data: Dictionary

func _init(record_data: Dictionary = {}) -> void:
	data = record_data.duplicate(true)

static func capture(npc: SimNPC) -> NPCStateRecord:
	return NPCStateRecord.new({
		"schema_version": SCHEMA_VERSION,
		"id": npc.id,
		"name": npc.npc_name,
		"profession": String(npc.profession),
		"hunger": npc.hunger,
		"energy": npc.energy,
		"strength": npc.strength,
		"intelligence": npc.intelligence,
		"current_task": String(npc.current_task),
		"task_state": String(npc.task_state),
		"position": [npc.position.x, npc.position.y, npc.position.z],
		"is_starving": npc.is_starving,
		"starvation_ticks": npc.starvation_ticks,
		"starvation_death_threshold": npc.starvation_death_threshold,
		"is_dead": npc.is_dead,
		"task_duration": npc.task_duration,
		"task_progress": npc.task_progress,
		"task_complete": npc.task_complete,
		"target_id": String(npc.target_id),
		"last_task": String(npc.last_task),
		"random_seed": str(npc.random_source.seed),
		"random_state": str(npc.random_source.state)
	})

static func from_dictionary(record_data: Dictionary) -> NPCStateRecord:
	if int(record_data.get("schema_version", -1)) != SCHEMA_VERSION:
		return null
	if not record_data.has_all([
		"id", "name", "profession", "hunger", "energy", "strength",
		"intelligence", "current_task", "task_state", "position",
		"is_starving", "starvation_ticks", "starvation_death_threshold",
		"is_dead", "task_duration", "task_progress", "task_complete",
		"target_id", "last_task", "random_seed", "random_state"
	]):
		return null
	var saved_position = record_data["position"]
	if not saved_position is Array or saved_position.size() != 3:
		return null
	var profession_id := StringName(record_data["profession"])
	if SimulationDefinitions.get_profession(profession_id) == null:
		return null
	var action_id := StringName(record_data["current_task"])
	if (
		action_id not in [
			SimulationIds.ACTION_IDLE,
			SimulationIds.ACTION_DEAD
		]
		and SimulationDefinitions.get_action(action_id) == null
	):
		return null
	var last_action_id := StringName(record_data["last_task"])
	if (
		not last_action_id.is_empty()
		and SimulationDefinitions.get_action(last_action_id) == null
	):
		return null
	return NPCStateRecord.new(record_data)

func restore(debug_logs: bool) -> SimNPC:
	var random_source := RandomNumberGenerator.new()
	random_source.seed = String(data["random_seed"]).to_int()
	var npc := SimNPC.new(
		int(data["id"]),
		String(data["name"]),
		StringName(data["profession"]),
		float(data["strength"]),
		float(data["intelligence"]),
		random_source
	)
	var saved_position: Array = data["position"]
	npc.hunger = float(data["hunger"])
	npc.energy = float(data["energy"])
	npc.current_task = StringName(data["current_task"])
	npc.task_state = StringName(data["task_state"])
	npc.position = Vector3(
		float(saved_position[0]),
		float(saved_position[1]),
		float(saved_position[2])
	)
	npc.is_starving = bool(data["is_starving"])
	npc.starvation_ticks = int(data["starvation_ticks"])
	npc.starvation_death_threshold = int(data["starvation_death_threshold"])
	npc.is_dead = bool(data["is_dead"])
	npc.task_duration = float(data["task_duration"])
	npc.task_progress = float(data["task_progress"])
	npc.task_complete = bool(data["task_complete"])
	npc.target_id = StringName(data["target_id"])
	npc.last_task = StringName(data["last_task"])
	npc.random_source.state = String(data["random_state"]).to_int()
	npc.debug_logs = debug_logs
	return npc

func to_dictionary() -> Dictionary:
	return data.duplicate(true)
