extends SceneTree

var failures: Array[String] = []


func _initialize() -> void:
	call_deferred("_run")


func _run() -> void:
	var main_scene: Node = load("res://main.tscn").instantiate()
	root.add_child(main_scene)
	await process_frame
	await physics_frame

	var simulation_manager: Node = main_scene.get_node("SimulationManager")
	simulation_manager.set_process(false)

	_check(simulation_manager.npcs.size() == 3, "Baseline should create three NPCs")
	_check(
		main_scene.has_node("JajceWorld/TerrainRoot/Terrain3D"),
		"Playable runtime should instance the Jajce Terrain3D world"
	)
	var terrain: Terrain3D = main_scene.get_node("JajceWorld/TerrainRoot/Terrain3D")
	_check(
		terrain.get_camera() == main_scene.get_node("CameraRig/Camera3D"),
		"Runtime Terrain3D should bind to the gameplay camera"
	)
	_check(
		(
			not main_scene.has_node("World")
			and not main_scene.has_node("ResourceNodes")
			and not main_scene.has_node("ActivityMarkers")
		),
		"Runtime should not retain duplicate flat-world objects"
	)
	var resource_root := main_scene.get_node("JajceWorld/WorldObjects/ResourceNodes")
	_check(resource_root.get_child_count() == 4, "Runtime should contain four Jajce ResourceNodes")
	_check(
		simulation_manager.resource_states.size() == 4,
		"Simulation authority should bind all four Jajce resources"
	)

	var navigation_map: RID = main_scene.get_world_3d().navigation_map
	await _wait_for_navigation_map(navigation_map)
	NavigationServer3D.map_force_update(navigation_map)

	var fixed_origins := [Vector3(-6.0, 0.0, -4.0), Vector3(0.0, 0.0, 0.0), Vector3(6.0, 0.0, 4.0)]
	var destinations: Array[Vector3] = []
	for marker_path in [
		"JajceWorld/LegacyActivityMarkers/PantryMarker",
		"JajceWorld/LegacyActivityMarkers/GuardZone",
		"JajceWorld/LegacyActivityMarkers/StudyZone",
		"JajceWorld/LegacyActivityMarkers/RestZone"
	]:
		destinations.append(main_scene.get_node(marker_path).global_position)

	for resource in resource_root.get_children():
		destinations.append((resource as ResourceNode).interaction_point.global_position)

	for origin in fixed_origins:
		for destination in destinations:
			var path := NavigationServer3D.map_get_path(navigation_map, origin, destination, true)
			_check(
				not path.is_empty(),
				"Navigation path should exist from %s to %s" % [origin, destination]
			)

	var village := SimVillage.new()
	var worker := SimNPC.new(100, "BaselineWorker", SimulationIds.PROFESSION_SCHOLAR, 5.0, 5.0)
	worker.set_task(SimulationIds.ACTION_STUDY, 2.0)
	worker.start_working()
	var executor := ActionExecutionSystem.new()
	executor.advance_npc(worker, village)
	executor.advance_npc(worker, village)
	_check(worker.task_complete, "A two-tick working task should complete")

	var starving := SimNPC.new(101, "BaselineStarving", SimulationIds.PROFESSION_WANDERER, 5.0, 5.0)
	starving.hunger = 100.0
	starving.starvation_death_threshold = 1
	executor.advance_npc(starving, village)
	_check(starving.is_dead, "Starvation threshold should still kill an NPC")

	if failures.is_empty():
		print("[TEST] Jajce runtime passed: 3 NPCs, 4 resources, 24 navigation routes")
		quit(0)
		return

	for failure in failures:
		push_error("[TEST] " + failure)
	quit(1)


func _wait_for_navigation_map(navigation_map: RID) -> void:
	for attempt in 30:
		if (
			NavigationServer3D.map_get_iteration_id(navigation_map) > 0
			and not NavigationServer3D.map_get_regions(navigation_map).is_empty()
		):
			await physics_frame
			return
		await physics_frame
	_check(false, "Navigation map did not synchronize within 30 physics frames")


func _check(condition: bool, message: String) -> void:
	if not condition:
		failures.append(message)
