## ECS ([Entity] [Component] [System]) Singleton[br]
## The ECS class acts as the central manager for the entire ECS framework
##
## The [_ECS] class maintains the current active [World] and provides access to [QueryBuilder] for fetching [Entity]s based on their [Component]s.
##[br]
## This singleton allows any part of the game to interact with the ECS system seamlessly.
## [codeblock]
##     var entities = ECS.world.query.with_all([Transform, Velocity]).execute()
##     for entity in entities:
##         entity.get_component(Transform).position += entity.get_component(Velocity).direction * delta
## [/codeblock]
## This is also where you control the setup of the world and process loop of the ECS system.
##[codeblock]
##
##   func _read(delta):
##       ECS.world = world
##
##	 func _process(delta):
##	     ECS.process(delta)
##[/codeblock]
## or in the physics loop
##[codeblock]
##	 func _physics_process(delta):
##	     ECS.process(delta)
##[/codeblock]
class_name _ECS
extends Node

## Emitted when the world is changed with a ref to the new world
signal world_changed(world: World)
##  Emitted when the world is exited
signal world_exited

## The Current active [World] Instance[br]
## Holds a reference to the currently active [World], allowing access to the [member World.query] instance and any [Entity]s and [System]s within it.
var world: World:
	get:
		return world
	set(value):
		# Add the new world to the scenes
		world = value
		if world:
			if not world.is_inside_tree():
				# Add the world to the tree if it is not already
				get_tree().root.get_node("./Root").add_child(world)
			if not world.is_connected("tree_exited", _on_world_exited):
				world.connect("tree_exited", _on_world_exited)
		world_changed.emit(world)
		assert(GECSEditorDebuggerMessages.set_world(world) if debug else true, 'Debug Data')

## Are we in debug mode? Controlled by project setting gecs/debug_mode
var debug := ProjectSettings.get_setting(GecsSettings.SETTINGS_DEBUG_MODE, false)
## This is an array of functions that get called on the entities when they get added to the world (after they are ready)
var entity_preprocessors: Array[Callable] = []
## This is an array of functions that get called on the entities right before they get removed from the world
var entity_postprocessors: Array[Callable] = []
## A Wildcard for use in relatonship queries. Indicates can be any value for a relation
## or a target in a Relationship Pair ECS.wildcard
var wildcard = null


## This is called to process the current active [World] instance and the [System]s within it.
## You would call this in _process or _physics_process to update the [_ECS] system.[br]
## If you provide a group name it will run just that group otherwise it runs all groups[br]
## Example:
## 	[codeblock]ECS.world.process(world, 'my-system-group')[/codeblock]
func process(delta: float, group: String = "") -> void:
	world.process(delta, group)


## Get all components of a specific type from a list of entities[br]
## If the component does not exist on the entity it will return the default_component if provided or assert
func get_components(entities, component_type, default_component = null) -> Array:
	var components = []
	for entity in entities:
		var component = entity.components.get(component_type.resource_path, null)
		if not component and not default_component:
			assert(component, "Entity does not have component: " + str(component_type))
		if not component and default_component:
			component = default_component
		components.append(component)

	return components


## Called when the world is exited
func _on_world_exited() -> void:
	world = null
	world_exited.emit()
	assert(GECSEditorDebuggerMessages.exit_world() if debug else true, 'Debug Data')


func serialize(query: QueryBuilder, config: GECSSerializeConfig = null) -> GecsData:
	return GECSIO.serialize(query, config)


func save(gecs_data: GecsData, filepath: String, binary: bool = false) -> bool:
	return GECSIO.save(gecs_data, filepath, binary)


func deserialize(gecs_filepath: String) -> Array[Entity]:
	return GECSIO.deserialize(gecs_filepath)
