extends SceneTree

## Synthetic main-thread scene, ownership, boundary and timing regression for
## ADT water finalization.

const FINALIZER_SCRIPT := preload("res://src/render/liquid/adt_water_scene_finalizer.gd")
const FINALIZER_PATH := "res://src/render/liquid/adt_water_scene_finalizer.gd"
const LOADER_PATH := "res://src/scenes/streaming/streaming_world_loader.gd"


func _initialize() -> void:
	var failures: Array[String] = []
	_verify_invalid_and_dry_input(failures)
	_verify_build_attach_geometry_and_owner(failures)
	_verify_ownership_boundaries(failures)
	var elapsed_milliseconds := _verify_bounded_timing(failures)
	if not failures.is_empty():
		for failure in failures:
			push_error("ADT_WATER_SCENE_FINALIZER: %s" % failure)
		quit(1)
		return
	print(
		"ADT_WATER_SCENE_FINALIZER PASS cases=8 iterations=100 elapsed_ms=%.3f"
		% elapsed_milliseconds
	)
	quit(0)


func _verify_invalid_and_dry_input(failures: Array[String]) -> void:
	var finalizer: RefCounted = FINALIZER_SCRIPT.new()
	var tile_root := Node3D.new()
	_expect_null(
		finalizer.call("attach_water_scene", {}, Vector3.ZERO, tile_root, null),
		"empty water data returns null",
		failures
	)
	_expect_equal(tile_root.get_child_count(), 0, "empty data does not mutate tile", failures)
	_expect_null(
		finalizer.call("attach_water_scene", _synthetic_water_data(), Vector3.ZERO, null, null),
		"missing tile root returns null",
		failures
	)
	_expect_null(
		finalizer.call(
			"attach_water_scene",
			{"chunks": [{"origin": Vector3.ZERO, "liquids": []}]},
			Vector3.ZERO,
			tile_root,
			null
		),
		"dry parsed ADT returns null",
		failures
	)
	_expect_equal(tile_root.get_child_count(), 0, "dry data does not mutate tile", failures)
	tile_root.free()


func _verify_build_attach_geometry_and_owner(failures: Array[String]) -> void:
	var finalizer: RefCounted = FINALIZER_SCRIPT.new()
	var editor_scene_root := Node3D.new()
	var tile_root := Node3D.new()
	get_root().add_child(editor_scene_root)
	editor_scene_root.add_child(tile_root)

	var tile_origin := Vector3(10.0, 20.0, 30.0)
	var water_root: Node3D = finalizer.call(
		"attach_water_scene",
		_synthetic_water_data(tile_origin),
		tile_origin,
		tile_root,
		editor_scene_root
	)
	_expect_not_null(water_root, "synthetic liquid builds a water root", failures)
	if water_root != null:
		_expect_true(water_root.get_parent() == tile_root, "water root attached once", failures)
		_expect_equal(tile_root.get_child_count(), 1, "tile owns one water root", failures)
		_expect_true(water_root.owner == editor_scene_root, "water root editor owner", failures)
		_expect_equal(water_root.get_child_count(), 1, "one liquid surface grouped", failures)
		if water_root.get_child_count() == 1:
			var liquid_mesh_instance := water_root.get_child(0) as MeshInstance3D
			_expect_not_null(liquid_mesh_instance, "liquid child is MeshInstance3D", failures)
			if liquid_mesh_instance != null:
				_expect_true(
					liquid_mesh_instance.owner == editor_scene_root,
					"liquid child editor owner",
					failures
				)
				var liquid_mesh := liquid_mesh_instance.mesh as ArrayMesh
				_expect_not_null(liquid_mesh, "liquid surface has ArrayMesh", failures)
				if liquid_mesh != null:
					_expect_equal(
						liquid_mesh.surface_get_array_len(0),
						4,
						"one enabled liquid cell has four vertices",
						failures
					)
					_expect_equal(
						liquid_mesh.surface_get_array_index_len(0),
						6,
						"one enabled liquid cell has six indices",
						failures
					)
	editor_scene_root.free()


func _verify_ownership_boundaries(failures: Array[String]) -> void:
	var finalizer_source := FileAccess.get_file_as_string(FINALIZER_PATH)
	var loader_source := FileAccess.get_file_as_string(LOADER_PATH)
	_expect_true(
		finalizer_source.contains("ADT_BUILDER_SCRIPT.build_tile_water_scene"),
		"finalizer retains existing ADTBuilder implementation",
		failures
	)
	_expect_true(
		finalizer_source.contains("tile_root.add_child(water_root)"),
		"finalizer owns water subtree attachment",
		failures
	)
	_expect_equal(
		loader_source.count("_adt_water_scene_finalizer.attach_water_scene("),
		2,
		"both loader water paths delegate finalization",
		failures
	)
	_expect_false(
		loader_source.contains("_builder.build_tile_water_scene"),
		"loader no longer builds water scenes directly",
		failures
	)
	_expect_true(
		loader_source.contains("state[\"water_loaded\"] = true"),
		"loader retains water-loaded timing",
		failures
	)
	_expect_true(
		loader_source.contains("WATER_FINALIZE"),
		"loader retains finalization permit ownership",
		failures
	)


func _verify_bounded_timing(failures: Array[String]) -> float:
	var finalizer: RefCounted = FINALIZER_SCRIPT.new()
	var tile_root := Node3D.new()
	var started_microseconds := Time.get_ticks_usec()
	for _iteration in range(100):
		finalizer.call("attach_water_scene", {}, Vector3.ZERO, tile_root, null)
	var elapsed_milliseconds := float(Time.get_ticks_usec() - started_microseconds) / 1000.0
	_expect_true(elapsed_milliseconds < 1000.0, "100 empty attempts under 1 second", failures)
	_expect_equal(tile_root.get_child_count(), 0, "timing loop creates no nodes", failures)
	tile_root.free()
	return elapsed_milliseconds


func _synthetic_water_data(tile_origin: Vector3 = Vector3.ZERO) -> Dictionary:
	var liquid_mask := PackedByteArray()
	liquid_mask.resize(64)
	liquid_mask.fill(0)
	liquid_mask[0] = 1
	var liquid_heights := PackedFloat32Array()
	liquid_heights.resize(81)
	liquid_heights.fill(tile_origin.y + 5.0)
	return {
		"chunks": [{
			"origin": tile_origin,
			"liquids": [{
				"liquid_id": 7,
				"mask": liquid_mask,
				"heights": liquid_heights,
			}],
		}],
	}


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_null(value: Variant, label: String, failures: Array[String]) -> void:
	_expect_true(value == null, label, failures)


func _expect_not_null(value: Variant, label: String, failures: Array[String]) -> void:
	_expect_true(value != null, 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])
