extends SceneTree

const STREAMING_WORLD_LOADER := preload("res://src/scenes/streaming/streaming_world_loader.gd")
const ADT_BUILDER := preload("res://addons/mpq_extractor/loaders/adt_builder.gd")

var _failures := 0


func _initialize() -> void:
	_verify_empty_water_root_ownership()
	_verify_runtime_cache_ownership()

	if _failures > 0:
		push_error("Render runtime cache shutdown verification failed: %d issue(s)" % _failures)
		quit(1)
		return
	print("Render runtime cache shutdown verification passed.")
	quit(0)


func _verify_empty_water_root_ownership() -> void:
	var node_count_before := int(Performance.get_monitor(Performance.OBJECT_NODE_COUNT))
	var empty_water_root: Node3D = ADT_BUILDER.build_tile_water_scene({"chunks": []}, Vector3.ZERO)
	var node_count_after := int(Performance.get_monitor(Performance.OBJECT_NODE_COUNT))
	_expect(empty_water_root == null, "empty ADT liquid payload should not produce a water root")
	_expect(node_count_after == node_count_before, "empty ADT liquid payload should release its temporary water root")


func _verify_runtime_cache_ownership() -> void:
	var loader: Node = STREAMING_WORLD_LOADER.new()
	var static_m2_prototype := Node3D.new()
	var animated_m2_prototype := Node3D.new()
	var wmo_prototype := Node3D.new()

	var m2_prototype_cache_state: RefCounted = loader.get("_m2_prototype_cache_state")
	m2_prototype_cache_state.call("adopt_static_prototype", "static", static_m2_prototype)
	m2_prototype_cache_state.call("adopt_animated_prototype", "animated", animated_m2_prototype)
	loader.set("_wmo_prototype_cache", {"wmo": wmo_prototype})
	var m2_mesh_resource_cache_state: RefCounted = loader.get("_m2_mesh_resource_cache_state")
	m2_mesh_resource_cache_state.call("store_mesh", "mesh", ArrayMesh.new())
	m2_prototype_cache_state.call("mark_animation_static", "static")
	m2_prototype_cache_state.call("mark_model_missing", "missing")
	var wmo_render_cache_state: RefCounted = loader.get("_wmo_render_resource_cache_state")
	wmo_render_cache_state.call("remember_request", "render", "res://render.res")
	wmo_render_cache_state.call("complete_request_with_resource", "render", Resource.new())
	wmo_render_cache_state.call("remember_request", "missing", "res://missing.res")
	wmo_render_cache_state.call("complete_request_as_missing", "missing")
	var wmo_scene_cache_state: RefCounted = loader.get("_wmo_scene_resource_cache_state")
	wmo_scene_cache_state.call("remember_request", "scene", "res://scene.tscn")
	wmo_scene_cache_state.call("complete_request_with_scene", "scene", PackedScene.new())
	wmo_scene_cache_state.call("mark_missing", "missing")
	loader.set("_wmo_missing_cache", {"missing": true})
	loader.set("_shared_tex_cache", {"texture": ImageTexture.new()})

	loader.call("_release_runtime_caches_for_shutdown")

	_expect(not is_instance_valid(static_m2_prototype), "static M2 prototype should be freed")
	_expect(not is_instance_valid(animated_m2_prototype), "animated M2 prototype should be freed")
	_expect(not is_instance_valid(wmo_prototype), "WMO prototype should be freed")
	var m2_prototype_snapshot: Dictionary = m2_prototype_cache_state.call(
		"diagnostic_snapshot"
	)
	for state_key in m2_prototype_snapshot.keys():
		_expect(
			(m2_prototype_snapshot[state_key] as Array).is_empty(),
			"M2 prototype %s should be empty after shutdown" % state_key
		)
	for cache_name in [
		"_wmo_prototype_cache",
		"_wmo_missing_cache",
		"_shared_tex_cache",
	]:
		var cache: Dictionary = loader.get(cache_name)
		_expect(cache.is_empty(), "%s should be empty after shutdown" % cache_name)
	_expect(
		int(m2_mesh_resource_cache_state.call("mesh_count")) == 0,
		"M2 Mesh Resources should be empty after shutdown"
	)
	var wmo_render_snapshot: Dictionary = wmo_render_cache_state.call("diagnostic_snapshot")
	_expect(
		(wmo_render_snapshot["resource_paths"] as Array).is_empty(),
		"WMO render Resources should be empty after shutdown"
	)
	_expect(
		(wmo_render_snapshot["missing_paths"] as Array).is_empty(),
		"WMO render negative cache should be empty after shutdown"
	)
	_expect(
		(wmo_render_snapshot["request_paths"] as Array).is_empty(),
		"WMO render requests should be empty after shutdown"
	)
	var wmo_scene_snapshot: Dictionary = wmo_scene_cache_state.call("diagnostic_snapshot")
	for state_key in ["scene_paths", "missing_paths", "request_paths"]:
		_expect(
			(wmo_scene_snapshot[state_key] as Array).is_empty(),
			"WMO scene %s should be empty after shutdown" % state_key
		)

	loader.free()


func _expect(condition: bool, message: String) -> void:
	if condition:
		return
	_failures += 1
	push_error(message)
