class_name WmoSceneResourceFinalizer
extends RefCounted

## Polls cached WMO PackedScene requests and publishes validated outcomes.
## File-size admission, live fallback and attached Node lifetime remain caller-owned.

var _scene_cache_validator: Object
var _resource_loader_adapter: Object


func _init(
	scene_cache_validator: Object,
	resource_loader_adapter: Object = null
) -> void:
	_scene_cache_validator = scene_cache_validator
	_resource_loader_adapter = resource_loader_adapter


## Polls a detached pending snapshot in insertion order. Terminal requests are
## published as the exact validated PackedScene or the historical missing state.
func poll_terminal_requests(scene_resource_cache_state: RefCounted) -> int:
	if scene_resource_cache_state == null:
		return 0
	var completed_request_count := 0
	var request_paths: Dictionary = scene_resource_cache_state.call(
		"request_paths_snapshot"
	)
	for normalized_relative_path_variant in request_paths.keys():
		var normalized_relative_path := String(normalized_relative_path_variant)
		var resource_path := String(request_paths[normalized_relative_path_variant])
		var load_status := load_threaded_get_status(resource_path)
		if (
			load_status != ResourceLoader.THREAD_LOAD_LOADED
			and load_status != ResourceLoader.THREAD_LOAD_FAILED
		):
			continue
		if load_status != ResourceLoader.THREAD_LOAD_LOADED:
			scene_resource_cache_state.call(
				"complete_request_as_missing",
				normalized_relative_path
			)
			completed_request_count += 1
			continue
		var loaded_resource := load_threaded_get(resource_path)
		var loaded_scene := loaded_resource as PackedScene
		if is_scene_cache_current(loaded_scene):
			scene_resource_cache_state.call(
				"complete_request_with_scene",
				normalized_relative_path,
				loaded_scene
			)
		else:
			scene_resource_cache_state.call(
				"complete_request_as_missing",
				normalized_relative_path
			)
		completed_request_count += 1
	return completed_request_count


## Instantiates one Node3D probe, delegates the existing WMOBuilder metadata
## check and synchronously releases the probe before returning.
func is_scene_cache_current(scene: PackedScene) -> bool:
	if scene == null or _scene_cache_validator == null:
		return false
	var instantiated_node := scene.instantiate()
	if not (instantiated_node is Node3D):
		if instantiated_node != null:
			instantiated_node.free()
		return false
	var instance := instantiated_node as Node3D
	var is_current := bool(_scene_cache_validator.call(
		"is_scene_cache_current",
		instance
	))
	instance.free()
	return is_current


## Production ResourceLoader status boundary; injectable for synthetic tests.
func load_threaded_get_status(resource_path: String) -> int:
	if _resource_loader_adapter != null:
		return int(_resource_loader_adapter.call(
			"load_threaded_get_status",
			resource_path
		))
	return ResourceLoader.load_threaded_get_status(resource_path)


## Production ResourceLoader result boundary; injectable for synthetic tests.
func load_threaded_get(resource_path: String) -> Resource:
	if _resource_loader_adapter != null:
		return _resource_loader_adapter.call(
			"load_threaded_get",
			resource_path
		) as Resource
	return ResourceLoader.load_threaded_get(resource_path)
