extends SceneTree

## Asset-free terminal-I/O, validation, adoption, boundary and timing regression
## for the lightweight WMO render Resource finalizer.

const FINALIZER_SCRIPT := preload(
	"res://src/render/wmo/wmo_render_resource_finalizer.gd"
)
const CACHE_STATE_SCRIPT := preload(
	"res://src/render/wmo/wmo_render_resource_cache_state.gd"
)
const FINALIZER_PATH := "res://src/render/wmo/wmo_render_resource_finalizer.gd"
const CACHE_STATE_PATH := "res://src/render/wmo/wmo_render_resource_cache_state.gd"
const LOADER_PATH := "res://src/scenes/streaming/streaming_world_loader.gd"


class FakeWmoRenderResource extends Resource:
	var format_version: int = 0


class FakeResourceLoaderAdapter extends RefCounted:
	var status_by_path: Dictionary = {}
	var resource_by_path: Dictionary = {}
	var status_paths: Array[String] = []
	var loaded_paths: Array[String] = []

	func load_threaded_get_status(resource_path: String) -> int:
		status_paths.append(resource_path)
		return int(status_by_path.get(
			resource_path,
			ResourceLoader.THREAD_LOAD_IN_PROGRESS
		))

	func load_threaded_get(resource_path: String) -> Resource:
		loaded_paths.append(resource_path)
		return resource_by_path.get(resource_path) as Resource


func _initialize() -> void:
	var failures: Array[String] = []
	_verify_null_and_non_terminal_poll(failures)
	_verify_failed_and_loaded_poll_order(failures)
	_verify_loaded_resource_rejections(failures)
	_verify_current_resource_adoption(failures)
	_verify_validation_contract(failures)
	_verify_source_boundaries(failures)
	var elapsed_milliseconds := _verify_bounded_timing(failures)
	if not failures.is_empty():
		for failure in failures:
			push_error("WMO_RENDER_RESOURCE_FINALIZER: %s" % failure)
		quit(1)
		return
	print(
		"WMO_RENDER_RESOURCE_FINALIZER PASS cases=24 iterations=1000 elapsed_ms=%.3f"
		% elapsed_milliseconds
	)
	quit(0)


func _verify_null_and_non_terminal_poll(failures: Array[String]) -> void:
	var adapter := FakeResourceLoaderAdapter.new()
	var expected_resource := FakeWmoRenderResource.new()
	var finalizer: RefCounted = FINALIZER_SCRIPT.new(
		expected_resource.get_script(),
		2,
		adapter
	)
	_expect_equal(
		int(finalizer.call("poll_terminal_requests", null)),
		0,
		"null cache state is rejected",
		failures
	)
	var cache_state: RefCounted = CACHE_STATE_SCRIPT.new()
	cache_state.call(
		"remember_request",
		"world/pending.wmo",
		"res://cache/pending.res"
	)
	_expect_equal(
		int(finalizer.call("poll_terminal_requests", cache_state)),
		0,
		"non-terminal request remains pending",
		failures
	)
	_expect_true(
		bool(cache_state.call("has_request", "world/pending.wmo")),
		"pending request retained",
		failures
	)
	_expect_string_array(
		adapter.status_paths,
		["res://cache/pending.res"],
		"pending path polled once",
		failures
	)
	_expect_equal(adapter.loaded_paths.size(), 0, "pending request is not loaded", failures)


func _verify_failed_and_loaded_poll_order(failures: Array[String]) -> void:
	var adapter := FakeResourceLoaderAdapter.new()
	var valid_resource := FakeWmoRenderResource.new()
	valid_resource.format_version = 2
	var finalizer: RefCounted = FINALIZER_SCRIPT.new(
		valid_resource.get_script(),
		2,
		adapter
	)
	var cache_state: RefCounted = CACHE_STATE_SCRIPT.new()
	var requests := {
		"world/pending.wmo": "res://cache/pending.res",
		"world/failed.wmo": "res://cache/failed.res",
		"world/loaded.wmo": "res://cache/loaded.res",
	}
	for normalized_relative_path in requests:
		cache_state.call(
			"remember_request",
			normalized_relative_path,
			requests[normalized_relative_path]
		)
	adapter.status_by_path = {
		"res://cache/failed.res": ResourceLoader.THREAD_LOAD_FAILED,
		"res://cache/loaded.res": ResourceLoader.THREAD_LOAD_LOADED,
	}
	adapter.resource_by_path["res://cache/loaded.res"] = valid_resource
	_expect_equal(
		int(finalizer.call("poll_terminal_requests", cache_state)),
		2,
		"failed and loaded requests complete",
		failures
	)
	_expect_string_array(
		adapter.status_paths,
		[
			"res://cache/pending.res",
			"res://cache/failed.res",
			"res://cache/loaded.res",
		],
		"detached insertion order preserved",
		failures
	)
	_expect_string_array(
		adapter.loaded_paths,
		["res://cache/loaded.res"],
		"only loaded terminal Resource retrieved",
		failures
	)
	_expect_true(
		bool(cache_state.call("is_missing", "world/failed.wmo")),
		"failed request publishes missing",
		failures
	)
	_expect_true(
		cache_state.call("resource_for", "world/loaded.wmo") == valid_resource,
		"loaded Resource identity adopted",
		failures
	)
	_expect_true(
		bool(cache_state.call("has_request", "world/pending.wmo")),
		"non-terminal sibling stays pending",
		failures
	)


func _verify_loaded_resource_rejections(failures: Array[String]) -> void:
	var expected_resource := FakeWmoRenderResource.new()
	var adapter := FakeResourceLoaderAdapter.new()
	var finalizer: RefCounted = FINALIZER_SCRIPT.new(
		expected_resource.get_script(),
		2,
		adapter
	)
	var stale_resource := FakeWmoRenderResource.new()
	stale_resource.format_version = 1
	var rejected_resources := {
		"null": null,
		"wrong_script": Resource.new(),
		"stale": stale_resource,
	}
	var cache_state: RefCounted = CACHE_STATE_SCRIPT.new()
	for rejection_name in rejected_resources:
		var normalized_relative_path := "world/%s.wmo" % rejection_name
		var cache_path := "res://cache/%s.res" % rejection_name
		cache_state.call("remember_request", normalized_relative_path, cache_path)
		adapter.status_by_path[cache_path] = ResourceLoader.THREAD_LOAD_LOADED
		adapter.resource_by_path[cache_path] = rejected_resources[rejection_name]
	_expect_equal(
		int(finalizer.call("poll_terminal_requests", cache_state)),
		3,
		"all invalid loaded Resources complete",
		failures
	)
	for rejection_name in rejected_resources:
		_expect_true(
			bool(cache_state.call("is_missing", "world/%s.wmo" % rejection_name)),
			"%s Resource publishes missing" % rejection_name,
			failures
		)


func _verify_current_resource_adoption(failures: Array[String]) -> void:
	var current_resource := FakeWmoRenderResource.new()
	current_resource.format_version = 2
	var newer_resource := FakeWmoRenderResource.new()
	newer_resource.format_version = 5
	var adapter := FakeResourceLoaderAdapter.new()
	var finalizer: RefCounted = FINALIZER_SCRIPT.new(
		current_resource.get_script(),
		2,
		adapter
	)
	var cache_state: RefCounted = CACHE_STATE_SCRIPT.new()
	for resource_name in ["current", "newer"]:
		var cache_path := "res://cache/%s.res" % resource_name
		cache_state.call(
			"remember_request",
			"world/%s.wmo" % resource_name,
			cache_path
		)
		adapter.status_by_path[cache_path] = ResourceLoader.THREAD_LOAD_LOADED
	adapter.resource_by_path["res://cache/current.res"] = current_resource
	adapter.resource_by_path["res://cache/newer.res"] = newer_resource
	finalizer.call("poll_terminal_requests", cache_state)
	_expect_true(
		cache_state.call("resource_for", "world/current.wmo") == current_resource,
		"current exact Resource adopted",
		failures
	)
	_expect_true(
		cache_state.call("resource_for", "world/newer.wmo") == newer_resource,
		"newer exact Resource adopted",
		failures
	)


func _verify_validation_contract(failures: Array[String]) -> void:
	var resource := FakeWmoRenderResource.new()
	resource.format_version = 2
	var valid_finalizer: RefCounted = FINALIZER_SCRIPT.new(resource.get_script(), 2)
	_expect_true(
		bool(valid_finalizer.call("is_current_render_resource", resource)),
		"exact script and minimum format accepted",
		failures
	)
	var missing_script_finalizer: RefCounted = FINALIZER_SCRIPT.new(null, 2)
	_expect_false(
		bool(missing_script_finalizer.call("is_current_render_resource", resource)),
		"missing expected script rejects Resource",
		failures
	)
	_expect_false(
		bool(valid_finalizer.call("is_current_render_resource", null)),
		"null Resource rejected",
		failures
	)


func _verify_source_boundaries(failures: Array[String]) -> void:
	var loader_source := _read_text(LOADER_PATH, failures)
	var finalizer_source := _read_text(FINALIZER_PATH, failures)
	var cache_source := _read_text(CACHE_STATE_PATH, failures)
	_expect_true(
		loader_source.contains("WMO_RENDER_RESOURCE_FINALIZER_SCRIPT.new("),
		"loader composes finalizer",
		failures
	)
	_expect_true(
		loader_source.contains("_wmo_render_resource_finalizer.poll_terminal_requests("),
		"loader delegates terminal polling",
		failures
	)
	_expect_false(
		loader_source.contains("resource.get_script() == WMO_STREAMING_SCRIPT"),
		"loader releases script validation",
		failures
	)
	for required_token in [
		"ResourceLoader.load_threaded_get_status(resource_path)",
		"ResourceLoader.load_threaded_get(resource_path)",
		"resource.get_script() == _expected_resource_script",
		"complete_request_with_resource",
		"complete_request_as_missing",
	]:
		_expect_true(
			finalizer_source.contains(required_token),
			"finalizer owns %s" % required_token,
			failures
		)
	_expect_false(
		cache_source.contains("ResourceLoader."),
		"cache state remains free of ResourceLoader",
		failures
	)


func _verify_bounded_timing(failures: Array[String]) -> float:
	var resource := FakeWmoRenderResource.new()
	resource.format_version = 2
	var adapter := FakeResourceLoaderAdapter.new()
	var finalizer: RefCounted = FINALIZER_SCRIPT.new(
		resource.get_script(),
		2,
		adapter
	)
	var started_microseconds := Time.get_ticks_usec()
	for iteration in range(1000):
		var cache_state: RefCounted = CACHE_STATE_SCRIPT.new()
		var normalized_relative_path := "world/object_%d.wmo" % iteration
		var cache_path := "res://cache/object_%d.res" % iteration
		cache_state.call("remember_request", normalized_relative_path, cache_path)
		adapter.status_by_path[cache_path] = ResourceLoader.THREAD_LOAD_FAILED
		finalizer.call("poll_terminal_requests", cache_state)
	var elapsed_milliseconds := float(
		Time.get_ticks_usec() - started_microseconds
	) / 1000.0
	if elapsed_milliseconds >= 1000.0:
		failures.append(
			"1000 terminal polls took %.3fms (budget < 1000ms)"
			% elapsed_milliseconds
		)
	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 read %s" % path)
		return ""
	var source := file.get_as_text()
	file.close()
	return source


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


func _expect_false(value: bool, label: String, failures: Array[String]) -> void:
	if value:
		failures.append(label)


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


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