class_name M2AnimationLoadPipelineState
extends RefCounted

## Owns animated M2 threaded-load request records and the terminal finalize FIFO.
## The caller owns ResourceLoader I/O, permits, Nodes and prototype outcomes.

var _request_by_normalized_path: Dictionary = {}
var _finalize_records: Array[Dictionary] = []


## Records one normalized M2 path and ResourceLoader path. Empty or duplicate
## values are rejected without mutation.
func remember_request(normalized_relative_path: String, resource_path: String) -> bool:
	if normalized_relative_path.is_empty() or resource_path.is_empty():
		return false
	if _request_by_normalized_path.has(normalized_relative_path):
		return false
	_request_by_normalized_path[normalized_relative_path] = {
		"normalized": normalized_relative_path,
		"path": resource_path,
	}
	return true


## Returns whether one normalized path currently has a pending threaded request.
func has_request(normalized_relative_path: String) -> bool:
	return (
		not normalized_relative_path.is_empty()
		and _request_by_normalized_path.has(normalized_relative_path)
	)


## Returns detached pending records in their existing Dictionary insertion order.
func request_records_snapshot() -> Array[Dictionary]:
	var records: Array[Dictionary] = []
	for request_variant in _request_by_normalized_path.values():
		var request: Dictionary = request_variant
		records.append(request.duplicate())
	return records


## Removes one pending request and appends its terminal status to the finalize
## FIFO. Unknown paths are rejected without mutation.
func complete_request(normalized_relative_path: String, terminal_status: int) -> bool:
	if not _request_by_normalized_path.has(normalized_relative_path):
		return false
	var request: Dictionary = _request_by_normalized_path[normalized_relative_path]
	_request_by_normalized_path.erase(normalized_relative_path)
	var finalize_record := request.duplicate()
	finalize_record["status"] = terminal_status
	_finalize_records.append(finalize_record)
	return true


## Removes one pending request without enqueuing finalization.
func discard_request(normalized_relative_path: String) -> bool:
	return _request_by_normalized_path.erase(normalized_relative_path)


## Returns whether a terminal record is waiting for budgeted finalization.
func has_finalize_record() -> bool:
	return not _finalize_records.is_empty()


## Removes and returns the oldest terminal record. Empty means none is ready.
func pop_finalize_record() -> Dictionary:
	if _finalize_records.is_empty():
		return {}
	return _finalize_records.pop_front()


## Returns pending plus terminal-finalize work for existing renderer metrics.
func total_work_count() -> int:
	return _request_by_normalized_path.size() + _finalize_records.size()


## Returns the pending request count.
func pending_request_count() -> int:
	return _request_by_normalized_path.size()


## Returns the terminal finalize FIFO count.
func finalize_record_count() -> int:
	return _finalize_records.size()


## Clears request/finalize bookkeeping. The caller must drain ResourceLoader
## requests before orderly shutdown clear.
func clear() -> void:
	_request_by_normalized_path.clear()
	_finalize_records.clear()


## Returns detached request and finalize records without loaded Resources/Nodes.
func diagnostic_snapshot() -> Dictionary:
	var finalize_records: Array[Dictionary] = []
	for record in _finalize_records:
		finalize_records.append(record.duplicate())
	return {
		"requests": request_records_snapshot(),
		"finalize_records": finalize_records,
	}
