extends SceneTree

## Synthetic MultiMesh identity, transform order, render settings, ownership
## boundary and bounded-timing regression for static M2 batch materialization.

const MATERIALIZER_SCRIPT := preload(
	"res://src/render/m2/m2_static_batch_materializer.gd"
)
const MATERIALIZER_PATH := "res://src/render/m2/m2_static_batch_materializer.gd"
const LOADER_PATH := "res://src/scenes/streaming/streaming_world_loader.gd"


func _initialize() -> void:
	var failures: Array[String] = []
	_verify_batch_contract(failures)
	_verify_zero_visibility_contract(failures)
	_verify_invalid_inputs(failures)
	_verify_ownership_boundaries(failures)
	var elapsed_milliseconds := _verify_bounded_timing(failures)
	if not failures.is_empty():
		for failure in failures:
			push_error("M2_STATIC_BATCH_MATERIALIZER: %s" % failure)
		quit(1)
		return
	print(
		"M2_STATIC_BATCH_MATERIALIZER PASS cases=11 instances=10000 elapsed_ms=%.3f"
		% elapsed_milliseconds
	)
	quit(0)


func _verify_batch_contract(failures: Array[String]) -> void:
	var materializer = MATERIALIZER_SCRIPT.new()
	var parent_root := Node3D.new()
	get_root().add_child(parent_root)
	var mesh := ArrayMesh.new()
	var transforms: Array = [
		Transform3D(Basis.IDENTITY, Vector3.ZERO),
		Transform3D(Basis.IDENTITY, Vector3(1.0, 2.0, 3.0)),
		Transform3D(Basis.IDENTITY, Vector3(4.0, 5.0, 6.0)),
	]
	var multimesh_instance: MultiMeshInstance3D = materializer.materialize_batch(
		parent_root,
		"World\\Doodads\\StaticTree.m2",
		mesh,
		transforms,
		1,
		2,
		7,
		345.0,
		16.0,
		false
	)
	_expect_true(multimesh_instance != null, "valid batch returned", failures)
	_expect_same(multimesh_instance.get_parent(), parent_root, "batch attached once", failures)
	_expect_equal(parent_root.get_child_count(), 1, "one parent child", failures)
	_expect_string_equal(multimesh_instance.name, "StaticTree_7", "batch name", failures)
	_expect_equal(multimesh_instance.multimesh.transform_format, MultiMesh.TRANSFORM_3D, "3D transform format", failures)
	_expect_same(multimesh_instance.multimesh.mesh, mesh, "exact Mesh identity", failures)
	_expect_equal(multimesh_instance.multimesh.instance_count, 2, "instance count", failures)
	_expect_equal(
		multimesh_instance.cast_shadow,
		GeometryInstance3D.SHADOW_CASTING_SETTING_OFF,
		"shadow mode",
		failures
	)
	_expect_float_equal(multimesh_instance.visibility_range_end, 345.0, "visibility end", failures)
	_expect_float_equal(multimesh_instance.visibility_range_end_margin, 16.0, "visibility margin", failures)
	parent_root.free()


func _verify_zero_visibility_contract(failures: Array[String]) -> void:
	var materializer = MATERIALIZER_SCRIPT.new()
	var parent_root := Node3D.new()
	var multimesh_instance: MultiMeshInstance3D = materializer.materialize_batch(
		parent_root,
		"world/static.m2",
		ArrayMesh.new(),
		[Transform3D.IDENTITY],
		0,
		1,
		0,
		0.0,
		99.0,
		true
	)
	_expect_float_equal(multimesh_instance.visibility_range_end, 0.0, "disabled visibility unchanged", failures)
	_expect_equal(
		multimesh_instance.cast_shadow,
		GeometryInstance3D.SHADOW_CASTING_SETTING_ON,
		"enabled shadow mode",
		failures
	)
	parent_root.free()


func _verify_invalid_inputs(failures: Array[String]) -> void:
	var materializer = MATERIALIZER_SCRIPT.new()
	var parent_root := Node3D.new()
	var mesh := ArrayMesh.new()
	var transforms: Array = [Transform3D.IDENTITY]
	_expect_true(
		materializer.materialize_batch(
			null, "a.m2", mesh, transforms, 0, 1, 0, 0.0, 0.0, true
		) == null,
		"null parent rejected",
		failures
	)
	_expect_true(
		materializer.materialize_batch(
			parent_root, "a.m2", null, transforms, 0, 1, 0, 0.0, 0.0, true
		) == null,
		"null Mesh rejected",
		failures
	)
	_expect_true(
		materializer.materialize_batch(
			parent_root, "a.m2", mesh, [], 0, 1, 0, 0.0, 0.0, true
		) == null,
		"empty transforms rejected",
		failures
	)
	_expect_true(
		materializer.materialize_batch(
			parent_root, "a.m2", mesh, transforms, 0, 0, 0, 0.0, 0.0, true
		) == null,
		"zero count rejected",
		failures
	)
	_expect_equal(parent_root.get_child_count(), 0, "invalid input has no attachment", failures)
	parent_root.free()


func _verify_ownership_boundaries(failures: Array[String]) -> void:
	var materializer_source := FileAccess.get_file_as_string(MATERIALIZER_PATH)
	var loader_source := FileAccess.get_file_as_string(LOADER_PATH)
	var loader_adapter_source := _source_between(
		loader_source,
		"func _materialize_m2_group_batch(",
		"func _materialize_m2_animated_batch(",
		failures
	)
	_expect_true(
		loader_source.contains("M2_STATIC_BATCH_MATERIALIZER_SCRIPT.new()"),
		"loader composes materializer",
		failures
	)
	_expect_equal(
		loader_adapter_source.count("_m2_static_batch_materializer.materialize_batch("),
		1,
		"loader delegates once",
		failures
	)
	_expect_false(loader_adapter_source.contains("MultiMesh.new()"), "loader adapter omits MultiMesh construction", failures)
	_expect_false(loader_adapter_source.contains("set_instance_transform("), "loader adapter omits transform upload", failures)
	_expect_true(loader_adapter_source.contains("_set_editor_owner_recursive(multimesh_instance)"), "loader retains Editor ownership", failures)
	for required_materializer_rule in [
		"MultiMesh.TRANSFORM_3D",
		"multimesh.mesh = mesh",
		"multimesh.instance_count = instance_count",
		"multimesh.set_instance_transform(",
		"transforms[start_index + batch_offset]",
		"m2_parent_root.add_child(multimesh_instance)",
	]:
		_expect_true(
			materializer_source.contains(required_materializer_rule),
			"materializer owns %s" % required_materializer_rule,
			failures
		)
	for forbidden_dependency in [
		"ResourceLoader.",
		"FileAccess.",
		"WorkerThreadPool.",
		"RenderingServer.",
		".owner =",
		"_m2_build_jobs",
		"_render_budget_scheduler",
	]:
		_expect_false(
			materializer_source.contains(forbidden_dependency),
			"materializer omits %s ownership" % forbidden_dependency,
			failures
		)


func _verify_bounded_timing(failures: Array[String]) -> float:
	var materializer = MATERIALIZER_SCRIPT.new()
	var parent_root := Node3D.new()
	get_root().add_child(parent_root)
	var transforms: Array = []
	for instance_index in 10000:
		transforms.append(
			Transform3D(Basis.IDENTITY, Vector3(float(instance_index), 0.0, 0.0))
		)
	var started_microseconds := Time.get_ticks_usec()
	var multimesh_instance: MultiMeshInstance3D = materializer.materialize_batch(
		parent_root,
		"world/timing.m2",
		ArrayMesh.new(),
		transforms,
		0,
		10000,
		1,
		0.0,
		0.0,
		true
	)
	var elapsed_milliseconds := float(Time.get_ticks_usec() - started_microseconds) / 1000.0
	_expect_equal(multimesh_instance.multimesh.instance_count, 10000, "timing batch complete", failures)
	_expect_true(elapsed_milliseconds < 1000.0, "10000 transforms under one second", failures)
	parent_root.free()
	return elapsed_milliseconds


func _source_between(
	source: String,
	start_marker: String,
	end_marker: String,
	failures: Array[String]
) -> String:
	var start_offset := source.find(start_marker)
	var end_offset := source.find(end_marker, start_offset + start_marker.length())
	if start_offset < 0 or end_offset <= start_offset:
		failures.append("cannot isolate source between %s and %s" % [start_marker, end_marker])
		return ""
	return source.substr(start_offset, end_offset - start_offset)


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)


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


func _expect_float_equal(actual: float, expected: float, label: String, failures: Array[String]) -> void:
	if not is_equal_approx(actual, expected):
		failures.append("%s expected=%.6f actual=%.6f" % [label, expected, actual])


func _expect_string_equal(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)
