extends SceneTree

## Asset-free M2 resource observation identity, adoption, lifetime, boundary and
## bounded-timing regression.

const SNAPSHOT_SCRIPT := preload(
	"res://src/render/m2/m2_build_resource_snapshot.gd"
)
const SNAPSHOT_PATH := "res://src/render/m2/m2_build_resource_snapshot.gd"
const DISPATCH_PATH := "res://src/render/m2/m2_build_dispatch_planner.gd"
const STATIC_OBSERVER_PATH := "res://src/render/m2/m2_static_build_resource_observer.gd"
const CACHED_ANIMATION_OBSERVER_PATH := (
	"res://src/render/m2/m2_cached_animation_resource_observer.gd"
)
const LOADER_PATH := "res://src/scenes/streaming/streaming_world_loader.gd"


func _initialize() -> void:
	var failures: Array[String] = []
	_verify_initial_observation(failures)
	_verify_static_adoption_and_replacement(failures)
	_verify_detached_diagnostics(failures)
	_verify_engine_lifetime(failures)
	_verify_loader_and_dependency_boundaries(failures)
	var elapsed_milliseconds := _verify_bounded_timing(failures)
	if not failures.is_empty():
		for failure in failures:
			push_error("M2_BUILD_RESOURCE_SNAPSHOT: %s" % failure)
		quit(1)
		return
	print(
		"M2_BUILD_RESOURCE_SNAPSHOT PASS cases=12 iterations=20000 elapsed_ms=%.3f"
		% elapsed_milliseconds
	)
	quit(0)


func _verify_initial_observation(failures: Array[String]) -> void:
	var prototype := Node3D.new()
	var snapshot: RefCounted = SNAPSHOT_SCRIPT.new(
		"world/example.m2",
		prototype,
		true
	)
	_expect_string(
		String(snapshot.call("normalized_relative_path")),
		"world/example.m2",
		"normalized path retained",
		failures
	)
	_expect_same(
		snapshot.call("animated_prototype"),
		prototype,
		"animated prototype identity retained",
		failures
	)
	_expect_true(
		bool(snapshot.call("has_animated_prototype")),
		"animated availability",
		failures
	)
	_expect_true(
		bool(snapshot.call("animation_request_pending")),
		"animation pending retained",
		failures
	)
	_expect_false(bool(snapshot.call("has_static_mesh")), "static defaults empty", failures)
	_expect_false(
		bool(snapshot.call("static_model_missing")),
		"missing defaults false",
		failures
	)
	prototype.free()


func _verify_static_adoption_and_replacement(failures: Array[String]) -> void:
	var snapshot: RefCounted = SNAPSHOT_SCRIPT.new("world/static.m2", null, false)
	var first_mesh := ArrayMesh.new()
	var second_mesh := ArrayMesh.new()
	snapshot.call("adopt_static_observation", first_mesh, true)
	_expect_same(snapshot.call("static_mesh"), first_mesh, "first Mesh identity", failures)
	_expect_true(bool(snapshot.call("has_static_mesh")), "static available", failures)
	_expect_true(
		bool(snapshot.call("static_model_missing")),
		"contradictory missing flag retained",
		failures
	)
	snapshot.call("adopt_static_observation", second_mesh, false)
	_expect_same(
		snapshot.call("static_mesh"),
		second_mesh,
		"replacement Mesh identity",
		failures
	)
	_expect_false(
		bool(snapshot.call("static_model_missing")),
		"replacement missing flag",
		failures
	)
	snapshot.call("adopt_static_observation", null, true)
	_expect_false(bool(snapshot.call("has_static_mesh")), "Mesh may clear", failures)
	_expect_true(bool(snapshot.call("static_model_missing")), "terminal missing adopted", failures)


func _verify_detached_diagnostics(failures: Array[String]) -> void:
	var prototype := Node3D.new()
	var mesh := ArrayMesh.new()
	var snapshot: RefCounted = SNAPSHOT_SCRIPT.new("world/diag.m2", prototype, false)
	snapshot.call("adopt_static_observation", mesh, true)
	var diagnostics: Dictionary = snapshot.call("diagnostic_snapshot")
	_expect_true(
		diagnostics == {
			"normalized_relative_path": "world/diag.m2",
			"has_animated_prototype": true,
			"animation_request_pending": false,
			"has_static_mesh": true,
			"static_model_missing": true,
		},
		"diagnostic scalar contract",
		failures
	)
	_expect_false(diagnostics.values().has(prototype), "diagnostics omit prototype", failures)
	_expect_false(diagnostics.values().has(mesh), "diagnostics omit Mesh", failures)
	diagnostics["has_static_mesh"] = false
	var fresh: Dictionary = snapshot.call("diagnostic_snapshot")
	_expect_true(bool(fresh["has_static_mesh"]), "diagnostics detached", failures)
	prototype.free()


func _verify_engine_lifetime(failures: Array[String]) -> void:
	var prototype := Node3D.new()
	var snapshot: RefCounted = SNAPSHOT_SCRIPT.new("world/lifetime.m2", prototype, false)
	snapshot = null
	_expect_true(is_instance_valid(prototype), "snapshot release keeps Node valid", failures)
	prototype.free()


func _verify_loader_and_dependency_boundaries(failures: Array[String]) -> void:
	var loader_source := FileAccess.get_file_as_string(LOADER_PATH)
	var dispatch_source := FileAccess.get_file_as_string(DISPATCH_PATH)
	var static_observer_source := FileAccess.get_file_as_string(STATIC_OBSERVER_PATH)
	var cached_observer_source := FileAccess.get_file_as_string(
		CACHED_ANIMATION_OBSERVER_PATH
	)
	var snapshot_source := FileAccess.get_file_as_string(SNAPSHOT_PATH)
	for delegated_token in [
		"M2_BUILD_RESOURCE_SNAPSHOT_SCRIPT.new(",
		"resource_snapshot.call(\"animated_prototype\")",
		"resource_snapshot.call(\"static_mesh\")",
	]:
		_expect_true(
			loader_source.contains(delegated_token),
			"loader uses %s" % delegated_token,
			failures
		)
	_expect_true(
		static_observer_source.contains("\"adopt_static_observation\""),
		"static observer adopts snapshot",
		failures
	)
	_expect_true(
		cached_observer_source.contains("M2_BUILD_RESOURCE_SNAPSHOT_SCRIPT.new("),
		"cached animation observer produces snapshot",
		failures
	)
	_expect_true(
		dispatch_source.contains("resource_snapshot.call(\"animation_request_pending\")")
		and dispatch_source.contains("resource_snapshot.call(\"has_static_mesh\")"),
		"dispatch planner consumes typed snapshot",
		failures
	)
	for forbidden_token in [
		"queue_free",
		"free(",
		"ResourceLoader",
		"RenderingServer",
		"FileAccess",
		"WorkerThreadPool",
		"Thread",
		"Mutex",
	]:
		_expect_false(
			snapshot_source.contains(forbidden_token),
			"snapshot omits %s ownership" % forbidden_token,
			failures
		)


func _verify_bounded_timing(failures: Array[String]) -> float:
	var mesh := ArrayMesh.new()
	var started_microseconds := Time.get_ticks_usec()
	for iteration in range(20000):
		var snapshot: RefCounted = SNAPSHOT_SCRIPT.new(
			"world/%d.m2" % (iteration % 64),
			null,
			iteration % 5 == 0
		)
		snapshot.call(
			"adopt_static_observation",
			mesh if iteration % 3 == 0 else null,
			iteration % 7 == 0
		)
		snapshot.call("diagnostic_snapshot")
	var elapsed_milliseconds := (
		float(Time.get_ticks_usec() - started_microseconds) / 1000.0
	)
	_expect_true(
		elapsed_milliseconds < 1000.0,
		"20,000 snapshot cycles remain bounded",
		failures
	)
	return elapsed_milliseconds


func _expect_string(
	actual: String,
	expected: String,
	label: String,
	failures: Array[String]
) -> void:
	if actual != expected:
		failures.append("%s expected=%s actual=%s" % [label, expected, actual])


func _expect_same(
	actual: Variant,
	expected: Variant,
	label: String,
	failures: Array[String]
) -> void:
	if not is_same(actual, expected):
		failures.append(label)


func _expect_true(condition: bool, label: String, failures: Array[String]) -> void:
	if not condition:
		failures.append(label)


func _expect_false(condition: bool, label: String, failures: Array[String]) -> void:
	_expect_true(not condition, label, failures)
