class_name WmoRenderResourceCacheState
extends RefCounted

## Owns validated lightweight-WMO render resources and their load state.
## ResourceLoader I/O and cache-format validation remain caller responsibilities.

var _resources_by_normalized_path: Dictionary = {}
var _missing_normalized_paths: Dictionary = {}
var _request_cache_paths_by_normalized_path: Dictionary = {}


## Returns the validated cached Resource for a normalized WMO path, or null.
func resource_for(normalized_relative_path: String) -> Resource:
	if normalized_relative_path.is_empty():
		return null
	return _resources_by_normalized_path.get(normalized_relative_path) as Resource


## Returns whether a validated Resource is cached for the normalized WMO path.
func contains_resource(normalized_relative_path: String) -> bool:
	return (
		not normalized_relative_path.is_empty()
		and _resources_by_normalized_path.has(normalized_relative_path)
	)


## Returns whether the normalized WMO path is in the negative cache.
func is_missing(normalized_relative_path: String) -> bool:
	return (
		not normalized_relative_path.is_empty()
		and _missing_normalized_paths.has(normalized_relative_path)
	)


## Returns whether the normalized WMO path has a pending threaded load request.
func has_request(normalized_relative_path: String) -> bool:
	return (
		not normalized_relative_path.is_empty()
		and _request_cache_paths_by_normalized_path.has(normalized_relative_path)
	)


## Records one loader-owned threaded request. Cached, missing, duplicate or empty
## paths are rejected so each normalized WMO path has exactly one state.
func remember_request(normalized_relative_path: String, cache_path: String) -> bool:
	if normalized_relative_path.is_empty() or cache_path.is_empty():
		return false
	if (
			_resources_by_normalized_path.has(normalized_relative_path)
			or _missing_normalized_paths.has(normalized_relative_path)
			or _request_cache_paths_by_normalized_path.has(normalized_relative_path)
	):
		return false
	_request_cache_paths_by_normalized_path[normalized_relative_path] = cache_path
	return true


## Returns a detached normalized-path to cache-path snapshot for loader-owned
## ResourceLoader polling or shutdown draining.
func request_paths_snapshot() -> Dictionary:
	return _request_cache_paths_by_normalized_path.duplicate()


## Completes a pending request with a caller-validated Resource. Returns false
## for unknown requests or null Resources and otherwise adopts the reference.
func complete_request_with_resource(
		normalized_relative_path: String,
		validated_resource: Resource
) -> bool:
	if (
			normalized_relative_path.is_empty()
			or validated_resource == null
			or not _request_cache_paths_by_normalized_path.has(normalized_relative_path)
	):
		return false
	_request_cache_paths_by_normalized_path.erase(normalized_relative_path)
	_missing_normalized_paths.erase(normalized_relative_path)
	_resources_by_normalized_path[normalized_relative_path] = validated_resource
	return true


## Completes a pending request as missing after load failure or validation
## rejection. Returns false for an unknown request.
func complete_request_as_missing(normalized_relative_path: String) -> bool:
	if (
			normalized_relative_path.is_empty()
			or not _request_cache_paths_by_normalized_path.has(normalized_relative_path)
	):
		return false
	_request_cache_paths_by_normalized_path.erase(normalized_relative_path)
	_resources_by_normalized_path.erase(normalized_relative_path)
	_missing_normalized_paths[normalized_relative_path] = true
	return true


## Clears pending requests and negative entries while retaining validated
## Resources for map reset or orderly shutdown request draining.
func clear_transient_state() -> void:
	_request_cache_paths_by_normalized_path.clear()
	_missing_normalized_paths.clear()


## Releases every cached Resource and transient entry. Safe to call repeatedly.
func clear_all() -> void:
	_resources_by_normalized_path.clear()
	clear_transient_state()


## Returns the number of pending threaded load requests.
func pending_request_count() -> int:
	return _request_cache_paths_by_normalized_path.size()


## Returns detached, sorted scalar keys without exposing Resource references.
func diagnostic_snapshot() -> Dictionary:
	var resource_paths: Array = _resources_by_normalized_path.keys()
	var missing_paths: Array = _missing_normalized_paths.keys()
	var request_paths: Array = _request_cache_paths_by_normalized_path.keys()
	resource_paths.sort()
	missing_paths.sort()
	request_paths.sort()
	return {
		"resource_paths": resource_paths.duplicate(),
		"missing_paths": missing_paths.duplicate(),
		"request_paths": request_paths.duplicate(),
	}
