extends SceneTree

## Asset-free ownership, lifecycle, dependency and timing regression for M2 IDs.

const REGISTRY_SCRIPT := preload("res://src/render/m2/m2_unique_placement_registry.gd")
const LOADER_PATH := "res://src/scenes/streaming/streaming_world_loader.gd"


func _initialize() -> void:
	var failures: Array[String] = []
	_verify_unkeyed_and_invalid_placements(failures)
	_verify_same_tile_and_cross_tile_deduplication(failures)
	_verify_owner_checked_release_and_retry(failures)
	_verify_clear_and_detached_diagnostics(failures)
	_verify_loader_boundary(failures)
	var elapsed_milliseconds := _verify_bounded_timing(failures)
	if not failures.is_empty():
		for failure in failures:
			push_error("M2_UNIQUE_PLACEMENT_REGISTRY: %s" % failure)
		quit(1)
		return
	print(
		"M2_UNIQUE_PLACEMENT_REGISTRY PASS cases=10 iterations=100 elapsed_ms=%.3f"
		% elapsed_milliseconds
	)
	quit(0)


func _verify_unkeyed_and_invalid_placements(failures: Array[String]) -> void:
	var registry: RefCounted = REGISTRY_SCRIPT.new()
	var result: Dictionary = registry.call("reserve", "tile-a", [
		{"unique_id": -1},
		{"unique_id": 0},
		{"name_id": 7},
		"invalid",
	])
	_expect_equal((result["placements"] as Array).size(), 3, "unkeyed placements pass", failures)
	_expect_true((result["unique_keys"] as Array).is_empty(), "unkeyed placements not owned", failures)
	_expect_equal(int(registry.call("active_count")), 0, "unkeyed active count", failures)


func _verify_same_tile_and_cross_tile_deduplication(failures: Array[String]) -> void:
	var registry: RefCounted = REGISTRY_SCRIPT.new()
	var placement := {"unique_id": 11785, "name_id": 0}
	var first: Dictionary = registry.call("reserve", "30_49", [placement, placement])
	_expect_equal((first["placements"] as Array).size(), 1, "same call duplicate filtered", failures)
	_expect_string_array((first["unique_keys"] as Array), ["uid:11785"], "first owner key", failures)
	var same_owner_retry: Dictionary = registry.call("reserve", "30_49", [placement])
	_expect_equal((same_owner_retry["placements"] as Array).size(), 1, "same owner later call passes", failures)
	var competing: Dictionary = registry.call("reserve", "31_49", [placement, placement])
	_expect_true((competing["placements"] as Array).is_empty(), "competing tile filtered", failures)
	_expect_string_array(
		competing["skipped_unique_keys"] as Array,
		["uid:11785"],
		"competing skip recorded once",
		failures
	)


func _verify_owner_checked_release_and_retry(failures: Array[String]) -> void:
	var registry: RefCounted = REGISTRY_SCRIPT.new()
	var placement := {"unique_id": 44}
	registry.call("reserve", "owner", [placement])
	_expect_true(
		(registry.call("release", "other", ["uid:44"]) as Array).is_empty(),
		"non-owner release ignored",
		failures
	)
	_expect_equal(int(registry.call("active_count")), 1, "non-owner keeps reservation", failures)
	var released: Array = registry.call("release", "owner", ["", "uid:44", "uid:44"])
	_expect_string_array(released, ["uid:44"], "owner release order and dedupe", failures)
	var retried: Dictionary = registry.call("reserve", "other", [placement])
	_expect_equal((retried["placements"] as Array).size(), 1, "waiting tile reserves after release", failures)


func _verify_clear_and_detached_diagnostics(failures: Array[String]) -> void:
	var registry: RefCounted = REGISTRY_SCRIPT.new()
	registry.call("reserve", "tile-b", [{"unique_id": 20}])
	registry.call("reserve", "tile-a", [{"unique_id": 10}])
	var snapshot: Dictionary = registry.call("diagnostic_snapshot")
	var owners: Array = snapshot["owners"]
	_expect_equal(int(snapshot["active_count"]), 2, "diagnostic count", failures)
	_expect_string_equal(String(owners[0]["unique_key"]), "uid:10", "diagnostic sorted", failures)
	owners[0]["tile_key"] = "mutated"
	var fresh_snapshot: Dictionary = registry.call("diagnostic_snapshot")
	_expect_string_equal(
		String((fresh_snapshot["owners"] as Array)[0]["tile_key"]),
		"tile-a",
		"diagnostics detached",
		failures
	)
	registry.call("clear")
	registry.call("clear")
	_expect_equal(int(registry.call("active_count")), 0, "clear idempotent", failures)


func _verify_loader_boundary(failures: Array[String]) -> void:
	var source := _read_text(LOADER_PATH, failures)
	_expect_true(source.contains("M2_UNIQUE_PLACEMENT_REGISTRY_SCRIPT.new()"), "loader composes registry", failures)
	_expect_true(source.contains("_m2_unique_placement_registry.reserve("), "loader delegates reserve", failures)
	_expect_true(source.contains("_m2_unique_placement_registry.release("), "loader delegates release", failures)
	_expect_true(source.contains("_m2_unique_placement_registry.clear()"), "loader delegates clear", failures)
	_expect_true(not source.contains("var _m2_unique_registry"), "loader omits registry dictionary", failures)
	_expect_true(not source.contains("func _m2_unique_key("), "loader omits key formula", failures)


func _verify_bounded_timing(failures: Array[String]) -> float:
	var placements: Array = []
	for placement_index in range(256):
		placements.append({"unique_id": placement_index + 1})
	var registry: RefCounted = REGISTRY_SCRIPT.new()
	var started_microseconds := Time.get_ticks_usec()
	for _iteration in range(100):
		var reservation: Dictionary = registry.call("reserve", "owner", placements)
		registry.call("release", "owner", reservation["unique_keys"])
	var elapsed_milliseconds := float(Time.get_ticks_usec() - started_microseconds) / 1000.0
	_expect_true(elapsed_milliseconds < 1000.0, "100 reserve/release cycles remain bounded", failures)
	return elapsed_milliseconds


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_string_equal(
		actual_value: String,
		expected_value: String,
		label: String,
		failures: Array[String]
) -> void:
	if actual_value != expected_value:
		failures.append("%s expected %s, got %s" % [label, expected_value, actual_value])


func _expect_string_array(
		actual_values: Array,
		expected_values: Array,
		label: String,
		failures: Array[String]
) -> void:
	if actual_values != expected_values:
		failures.append("%s expected %s, got %s" % [label, expected_values, actual_values])


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