extends SceneTree

## Asset-free ordering, cursor, dependency and timing regression for WMO builds.

const PLANNER_SCRIPT := preload("res://src/render/wmo/wmo_render_build_step_planner.gd")
const PLANNER_PATH := "res://src/render/wmo/wmo_render_build_step_planner.gd"
const LOADER_PATH := "res://src/scenes/streaming/streaming_world_loader.gd"


func _initialize() -> void:
	var failures: Array[String] = []
	_verify_mesh_steps_precede_multimeshes(failures)
	_verify_multimesh_cursor_and_completion(failures)
	_verify_empty_and_raw_integer_behavior(failures)
	_verify_fresh_results(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("WMO_RENDER_BUILD_STEP_PLANNER: %s" % failure)
		quit(1)
		return
	print(
		"WMO_RENDER_BUILD_STEP_PLANNER PASS cases=9 iterations=20000 elapsed_ms=%.3f"
		% elapsed_milliseconds
	)
	quit(0)


func _verify_mesh_steps_precede_multimeshes(failures: Array[String]) -> void:
	var planner: RefCounted = PLANNER_SCRIPT.new()
	var first: Dictionary = planner.call("plan_step", 2, 0, 3, 0)
	_expect_operation(first, PLANNER_SCRIPT.OPERATION_MESH, 0, 1, 0, "first mesh", failures)
	var second: Dictionary = planner.call("plan_step", 2, 1, 3, 0)
	_expect_operation(second, PLANNER_SCRIPT.OPERATION_MESH, 1, 2, 0, "second mesh", failures)
	var after_meshes: Dictionary = planner.call("plan_step", 2, 2, 3, 0)
	_expect_operation(
		after_meshes,
		PLANNER_SCRIPT.OPERATION_MULTIMESH,
		0,
		2,
		1,
		"multimesh follows meshes",
		failures
	)


func _verify_multimesh_cursor_and_completion(failures: Array[String]) -> void:
	var planner: RefCounted = PLANNER_SCRIPT.new()
	var last_multimesh: Dictionary = planner.call("plan_step", 1, 1, 2, 1)
	_expect_operation(
		last_multimesh,
		PLANNER_SCRIPT.OPERATION_MULTIMESH,
		1,
		1,
		2,
		"last multimesh",
		failures
	)
	var complete: Dictionary = planner.call("plan_step", 1, 1, 2, 2)
	_expect_operation(
		complete,
		PLANNER_SCRIPT.OPERATION_COMPLETE,
		-1,
		1,
		2,
		"both ranges complete",
		failures
	)


func _verify_empty_and_raw_integer_behavior(failures: Array[String]) -> void:
	var planner: RefCounted = PLANNER_SCRIPT.new()
	var empty: Dictionary = planner.call("plan_step", 0, 0, 0, 0)
	_expect_operation(empty, PLANNER_SCRIPT.OPERATION_COMPLETE, -1, 0, 0, "empty", failures)
	var negative_mesh_cursor: Dictionary = planner.call("plan_step", 1, -1, 0, 0)
	_expect_operation(
		negative_mesh_cursor,
		PLANNER_SCRIPT.OPERATION_MESH,
		-1,
		0,
		0,
		"negative mesh cursor is not clamped",
		failures
	)
	var negative_counts: Dictionary = planner.call("plan_step", -1, 0, -1, 0)
	_expect_operation(
		negative_counts,
		PLANNER_SCRIPT.OPERATION_COMPLETE,
		-1,
		0,
		0,
		"negative counts preserve comparisons",
		failures
	)


func _verify_fresh_results(failures: Array[String]) -> void:
	var planner: RefCounted = PLANNER_SCRIPT.new()
	var first: Dictionary = planner.call("plan_step", 1, 0, 0, 0)
	first["next_mesh_index"] = 99
	var second: Dictionary = planner.call("plan_step", 1, 0, 0, 0)
	_expect_equal(int(second["next_mesh_index"]), 1, "result is fresh", failures)


func _verify_loader_and_dependency_boundaries(failures: Array[String]) -> void:
	var loader_source := _read_text(LOADER_PATH, failures)
	var planner_source := _read_text(PLANNER_PATH, failures)
	_expect_true(
		loader_source.contains("WMO_RENDER_BUILD_STEP_PLANNER_SCRIPT.new()"),
		"loader composes planner",
		failures
	)
	_expect_true(
		loader_source.contains("_wmo_render_build_step_planner.plan_step("),
		"loader delegates step decision",
		failures
	)
	_expect_true(
		loader_source.contains("MeshInstance3D.new()")
		and loader_source.contains("MultiMeshInstance3D.new()"),
		"loader retains node materialization",
		failures
	)
	_expect_false(
		loader_source.contains("if mesh_index < meshes.size():"),
		"loader omits mesh cursor decision",
		failures
	)
	for forbidden_token in [
		"extends Node", "Node3D", "Resource", "Mesh", "RID", "Thread", "Mutex", "FileAccess"
	]:
		_expect_false(
			planner_source.contains(forbidden_token),
			"planner omits %s dependency" % forbidden_token,
			failures
		)


func _verify_bounded_timing(failures: Array[String]) -> float:
	var planner: RefCounted = PLANNER_SCRIPT.new()
	var started_microseconds := Time.get_ticks_usec()
	var checksum := 0
	for iteration in range(20000):
		var step: Dictionary = planner.call(
			"plan_step",
			48,
			iteration % 49,
			24,
			iteration % 25
		)
		checksum += int(step["selected_index"])
	var elapsed_milliseconds := float(Time.get_ticks_usec() - started_microseconds) / 1000.0
	_expect_true(checksum > 0, "timing checksum", failures)
	_expect_true(elapsed_milliseconds < 1000.0, "20,000 plans remain bounded", failures)
	return elapsed_milliseconds


func _expect_operation(
		actual_step: Dictionary,
		expected_operation: StringName,
		expected_selected_index: int,
		expected_next_mesh_index: int,
		expected_next_multimesh_index: int,
		label: String,
		failures: Array[String]
) -> void:
	if actual_step["operation"] != expected_operation:
		failures.append(
			"%s operation expected %s, got %s"
			% [label, expected_operation, actual_step["operation"]]
		)
	_expect_equal(
		int(actual_step["selected_index"]),
		expected_selected_index,
		"%s selected" % label,
		failures
	)
	_expect_equal(
		int(actual_step["next_mesh_index"]),
		expected_next_mesh_index,
		"%s next mesh" % label,
		failures
	)
	_expect_equal(
		int(actual_step["next_multimesh_index"]),
		expected_next_multimesh_index,
		"%s next multimesh" % label,
		failures
	)


func _read_text(path: String, failures: Array[String]) -> String:
	var file := FileAccess.open(path, FileAccess.READ)
	if file == null:
		failures.append("cannot open %s" % path)
		return ""
	return file.get_as_text()


func _expect_equal(actual_value: int, expected_value: int, label: String, failures: Array[String]) -> void:
	if actual_value != expected_value:
		failures.append("%s expected %d, got %d" % [label, expected_value, actual_value])


func _expect_true(actual_value: bool, label: String, failures: Array[String]) -> void:
	if not actual_value:
		failures.append("%s expected true" % label)


func _expect_false(actual_value: bool, label: String, failures: Array[String]) -> void:
	if actual_value:
		failures.append("%s expected false" % label)
