import EntityManager from "./entity-manager";
import EventBus from "./event-bus";
import { type ResourceFactoryWithDeps, type ResourceDirectValue } from "./resource-manager";
import AssetManager from "./asset-manager";
import ScreenManager from "./screen-manager";
import { type ReactiveQueryDefinition } from "./reactive-query-manager";
import CommandBuffer from "./command-buffer";
import type { System, SystemPhase, FilteredEntity, Entity, RemoveEntityOptions, HierarchyEntry, HierarchyIteratorOptions } from "./types";
import { type Plugin } from "./plugin";
import { SystemBuilder } from "./system-builder";
import type { AssetDefinition, AssetHandle } from "./asset-types";
import type { ScreenDefinition } from "./screen-types";
import { ECSpressoBuilder } from "./ecspresso-builder";
import type { WorldConfig, EmptyConfig, ConflictingSlot, MissingRequirementSlot } from "./type-utils";
/**
    * Interface declaration for ECSpresso constructor to ensure type augmentation works properly.
    * This merges with the class declaration below.
*/
export default interface ECSpresso<Cfg extends WorldConfig = EmptyConfig, Labels extends string = string, Groups extends string = string, AssetGroupNames extends string = string, ReactiveQueryNames extends string = string> {
    /**
        * Default constructor
    */
    new (): ECSpresso<Cfg, Labels, Groups, AssetGroupNames, ReactiveQueryNames>;
}
/**
 * Branded sentinel used as the expected-parameter type when `installPlugin`
 * detects an incompatible or unsatisfied plugin. The template-literal message
 * surfaces in the TypeScript error, pointing at the failing WorldConfig slot.
 * Uninhabitable at the value level (the symbol key is unreachable), so the
 * argument is still rejected.
 */
declare const __pluginError: unique symbol;
export type PluginError<M extends string> = {
    readonly [__pluginError]: M;
};
/**
 * Resolves to the expected parameter type for `installPlugin` given a world
 * config and a plugin's generic parameters:
 * - `Plugin<PCfg, PReq, ...>` when compatible and all requirements are met.
 * - `PluginError<"Plugin's X conflict with this world...">` when any slot conflicts.
 * - `PluginError<"Plugin requires X not provided by this world">` when a requirement is missing.
 *
 * Exported so tests can assert the exact parameter type `installPlugin`
 * produces without duplicating the conditional logic.
 */
export type InstallPluginParam<Cfg extends WorldConfig, PCfg extends WorldConfig, PReq extends WorldConfig, BL extends string, BG extends string, BAG extends string, BRQ extends string> = [
    ConflictingSlot<Cfg, PCfg>
] extends [never] ? [MissingRequirementSlot<Cfg, PReq>] extends [never] ? Plugin<PCfg, PReq, BL, BG, BAG, BRQ> : PluginError<`Plugin requires ${MissingRequirementSlot<Cfg, PReq>} not provided by this world`> : PluginError<`Plugin's ${ConflictingSlot<Cfg, PCfg>} conflict with this world (same key, different type)`>;
/**
    * ECSpresso is the central ECS framework class that connects all features.
    * It handles creation and management of entities, components, and systems, and provides lifecycle hooks.
*/
export default class ECSpresso<Cfg extends WorldConfig = EmptyConfig, Labels extends string = string, Groups extends string = string, AssetGroupNames extends string = string, ReactiveQueryNames extends string = string> {
    readonly _cfg: Cfg;
    /** Library version*/
    static readonly VERSION: string;
    /** Access/modify stored components and entities*/
    private _entityManager;
    /** Publish/subscribe to events*/
    private _eventBus;
    /** Access/modify registered resources*/
    private _resourceManager;
    /** Command buffer for deferred structural changes */
    private _commandBuffer;
    /** Registered systems that will be updated in order*/
    private _systems;
    /** Systems grouped by execution phase, each sorted by priority */
    private _phaseSystems;
    /** Track installed plugins to prevent duplicates*/
    private _installedPlugins;
    /** Per-plugin disposers registered via the install function's second arg */
    private _pluginCleanups;
    /** Defaults applied to systems created via addSystem during a plugin's install */
    private _currentSystemDefaults;
    /** Entity IDs scoped to a specific screen — removed on that screen's exit */
    private _screenScopedEntities;
    /** Reverse index: entity ID -> scope screen name, for O(1) cleanup on remove */
    private _entityScreenScope;
    /**
     * Active screen scope hint set during a screen-gated system's process tick.
     * spawn / spawnChild / commands.spawn fall back to this when the caller did
     * not pass an explicit `scope`. `null` means no hint (not in a gated tick,
     * or system has no `inScreens` matching the current screen).
     */
    private _activeScopeHint;
    /** Disabled system groups */
    private _disabledGroups;
    /** Asset manager for loading and accessing assets */
    private _assetManager;
    /** Screen manager for state/screen transitions */
    private _screenManager;
    /** Reactive query manager for enter/exit callbacks */
    private _reactiveQueryManager;
    /** Post-update hooks to be called after all systems in update() */
    private _postUpdateHooks;
    /** Global tick counter, incremented at the end of each update() */
    private _currentTick;
    /** Per-system last-seen change sequence for change detection */
    private _systemLastSeqs;
    /** Change threshold used for public getEntitiesWithQuery and between-system resolution */
    private _changeThreshold;
    /** Fixed timestep interval in seconds (default: 1/60) */
    private _fixedDt;
    /** Accumulated time for fixed update steps */
    private _fixedAccumulator;
    /** Interpolation alpha between fixed steps (accumulator / fixedDt) */
    private _interpolationAlpha;
    /** Maximum fixed update steps per frame (spiral-of-death protection) */
    private _maxFixedSteps;
    /** Registry of required component relationships: trigger -> [{component, factory}] */
    private _requiredComponents;
    /** Pending plugin assets awaiting manager creation at build time */
    private _pendingPluginAssets;
    /** Pending plugin screens awaiting manager creation at build time */
    private _pendingPluginScreens;
    /** Whether diagnostics timing collection is enabled */
    private _diagnosticsEnabled;
    /** Per-system timing in ms, populated when diagnostics enabled */
    private _systemTimings;
    /** Per-phase timing in ms, populated when diagnostics enabled */
    private _phaseTimings;
    /** Per-system per-query seen entity IDs for onEntityEnter tracking */
    private _entityEnterTracking;
    /** Shared reusable set for per-tick entity enter comparison (avoids allocation) */
    private _entityEnterFrameSet;
    /** Pre-allocated process context per system (avoids per-frame allocation) */
    private _systemContexts;
    /** Shared scratch array for singleton query resolution (cleared and reused each resolution) */
    private _singletonScratch;
    /** Pending system builder finalizers to run before next update/initialize */
    private _pendingFinalizers;
    private _batchingRegistrations;
    /** Whether `initialize()` has completed — flips the onInitialize firing path for late-added systems */
    private _initializeFired;
    private _systemsInitialized;
    /**
        * Creates a new ECSpresso instance.
    */
    constructor();
    /**
     * Subscribes to EntityManager lifecycle hooks for change detection,
     * required component auto-addition, and reactive query tracking.
     * @private
     */
    private _subscribeLifecycleHooks;
    /**
        * Creates a new ECSpresso builder for type-safe plugin installation.
        * Types are inferred from the builder chain — use `.withPlugin()`,
        * `.withComponentTypes<T>()`, `.withEventTypes<T>()`, and `.withResource()`
        * to accumulate types without manual aggregate interfaces.
     *
        * @returns A builder instance for fluent method chaining
     *
        * @example
        * ```typescript
        * const ecs = ECSpresso.create()
     *	 .withPlugin(createRenderer2DPlugin({ ... }))
     *	 .withPlugin(createPhysics2DPlugin())
     *	 .withComponentTypes<{ player: true; enemy: { type: string } }>()
     *	 .withEventTypes<{ gameStart: true }>()
     *	 .withResource('score', { value: 0 })
     *	 .build();
     *
     * type ECS = typeof ecs;
        * ```
    */
    static create<Cfg2 extends WorldConfig = EmptyConfig>(): ECSpressoBuilder<Cfg2, never, never, never, never>;
    /**
        * Adds a system directly to this ECSpresso instance.
        * The system is registered when initialize() or update() is next called.
        * @param label Unique name to identify the system
        * @returns A SystemBuilder instance for method chaining
    */
    addSystem(label: string): SystemBuilder<Cfg>;
    /**
     * Finalize and register all pending system builders.
     * @private
     */
    private _finalizePendingBuilders;
    /**
     * Update all systems across execution phases.
     * Phases run in order: preUpdate -> fixedUpdate -> update -> postUpdate -> render.
     * The fixedUpdate phase uses a time accumulator for deterministic fixed-timestep simulation.
     * @param deltaTime Time elapsed since the last update (in seconds)
     */
    update(deltaTime: number): void;
    /**
     * Execute all systems in a single phase.
     * @private
     */
    private _executePhase;
    /**
     * Execute a non-fixed phase with optional timing, then play back the command buffer.
     * @private
     */
    private _runPhase;
    /**
     * Initialize all resources and systems
     * This method:
     * 1. Initializes all resources that were added as factory functions
     * 2. Sets up asset manager and loads eager assets
     * 3. Sets up screen manager
     * 4. Calls the onInitialize lifecycle hook on all systems
     *
     * This is useful for game startup to ensure all resources are ready
     * and systems are properly initialized before the game loop begins.
     *
     * @returns Promise that resolves when everything is initialized
     */
    initialize(): Promise<void>;
    /**
     * Initialize specific resources or all resources that were added as factory functions but haven't been initialized yet.
     * This is useful when you need to ensure resources are ready before proceeding.
     * @param keys Optional array of resource keys to initialize. If not provided, all pending resources will be initialized.
     * @returns Promise that resolves when the specified resources are initialized
     */
    initializeResources<K extends keyof Cfg['resources']>(...keys: K[]): Promise<void>;
    /**
     * Rebuild per-phase system arrays from the flat _systems list.
     * Each phase array is sorted by priority (higher first), with
     * registration order as tiebreaker.
     * @private
     */
    private _rebuildPhaseSystems;
    /**
        * Update the priority of a system
        * @param label The unique label of the system to update
        * @param priority The new priority value (higher values execute first)
        * @returns true if the system was found and updated, false otherwise
    */
    updateSystemPriority(label: Labels, priority: number): boolean;
    /**
     * Move a system to a different execution phase at runtime.
     * @param label The unique label of the system to move
     * @param phase The target phase
     * @returns true if the system was found and updated, false otherwise
     */
    updateSystemPhase(label: Labels, phase: SystemPhase): boolean;
    /**
     * The interpolation alpha between fixed update steps.
     * Ranges from 0 to <1, representing how far into the next
     * fixed step the current frame is. Use in the render phase
     * for smooth visual interpolation.
     */
    get interpolationAlpha(): number;
    /**
     * The configured fixed timestep interval in seconds.
     */
    get fixedDt(): number;
    /**
     * Disable a system group. Systems in this group will be skipped during update().
     * @param groupName The name of the group to disable
     */
    disableSystemGroup(groupName: Groups): void;
    /**
     * Enable a system group. Systems in this group will run during update().
     * @param groupName The name of the group to enable
     */
    enableSystemGroup(groupName: Groups): void;
    /**
     * Check if a system group is enabled.
     * @param groupName The name of the group to check
     * @returns true if the group is enabled (or doesn't exist), false if disabled
     */
    isSystemGroupEnabled(groupName: Groups): boolean;
    /**
     * Get all system labels that belong to a specific group.
     * @param groupName The name of the group
     * @returns Array of system labels in the group
     */
    getSystemsInGroup(groupName: Groups): string[];
    /**
        * Remove a system by its label
        * Calls the system's onDetach method with this ECSpresso instance if defined
        * @param label The unique label of the system to remove
        * @returns true if the system was found and removed, false otherwise
    */
    removeSystem(label: Labels): boolean;
    /**
        * Internal method to register a system with this ECSpresso instance
        * @internal Used by SystemBuilder - replaces direct private property access
    */
    _registerSystem(system: System<Cfg, any, any>): void;
    /**
        * Check if a resource exists
    */
    hasResource<K extends keyof Cfg['resources']>(key: K): boolean;
    /**
     * Get a resource by key. Throws if the resource is not found.
     * @param key The resource key
     * @returns The resource value
     * @throws Error if resource not found
     * @see tryGetResource — the non-throwing alternative that returns undefined
     */
    getResource<K extends keyof Cfg['resources']>(key: K): Cfg['resources'][K];
    /**
     * Try to get a resource by key. Returns undefined if the resource is not found.
     * Inspired by Bevy's `World::get_resource::<T>()` which returns `Option<&T>`.
     *
     * Two overloads:
     * 1. Known key — full type safety from `ResourceTypes`
     * 2. String key with explicit type param — for cross-plugin optional dependencies
     *
     * @example
     * ```typescript
     * // Known key (type inferred from ResourceTypes)
     * const score = ecs.tryGetResource('score'); // ScoreResource | undefined
     *
     * // Cross-plugin optional dependency (caller specifies expected type)
     * const si = ecs.tryGetResource<SpatialIndex>('spatialIndex') ?? null;
     * ```
     */
    tryGetResource<K extends keyof Cfg['resources']>(key: K): Cfg['resources'][K] | undefined;
    tryGetResource<T>(key: unknown extends T ? never : string): T | undefined;
    /**
        * Add a resource to the ECS instance.
        *
        * - Plain value → stored directly
        * - Function → treated as a factory, called with this ECSpresso instance on first access
        * - `{ factory, dependsOn?, onDispose? }` → factory with dependencies/disposal
        * - `directValue(val)` → stores the value as-is (use to store functions/classes without invoking them)
    */
    addResource<K extends keyof Cfg['resources']>(key: K, resource: Cfg['resources'][K] | ((ecs: ECSpresso<Cfg>) => Cfg['resources'][K] | Promise<Cfg['resources'][K]>) | ResourceFactoryWithDeps<Cfg['resources'][K], ECSpresso<Cfg>, keyof Cfg['resources'] & string> | ResourceDirectValue<Cfg['resources'][K]>): this;
    /**
        * Remove a resource from the ECS instance (without calling onDispose)
        * @param key The resource key to remove
        * @returns True if the resource was removed, false if it didn't exist
    */
    removeResource<K extends keyof Cfg['resources']>(key: K): boolean;
    /**
     * Dispose a single resource, calling its onDispose callback if defined
     * @param key The resource key to dispose
     * @returns True if the resource existed and was disposed, false if it didn't exist
     */
    disposeResource<K extends keyof Cfg['resources']>(key: K): Promise<boolean>;
    /**
     * Dispose all initialized resources in reverse dependency order.
     * Resources that depend on others are disposed first.
     * Calls each resource's onDispose callback if defined.
     */
    disposeResources(): Promise<void>;
    /**
        * Update an existing resource using an updater function
        * @param key The resource key to update
        * @param updater Function that receives the current resource value and returns the new value
        * @returns This ECSpresso instance for chaining
        * @throws Error if the resource doesn't exist
    */
    updateResource<K extends keyof Cfg['resources']>(key: K, updater: (current: Cfg['resources'][K]) => Cfg['resources'][K]): this;
    /**
        * Set a resource to a plain value.
        * Unlike updateResource, does not require an updater function.
        * @param key The resource key to set
        * @param value The new resource value
        * @returns This ECSpresso instance for chaining
    */
    setResource<K extends keyof Cfg['resources']>(key: K, value: Cfg['resources'][K]): this;
    /**
        * Subscribe to changes for a specific resource key.
        * @param key The resource key to watch
        * @param callback Function called with (newValue, oldValue) when the resource changes
        * @returns Unsubscribe function
    */
    onResourceChange<K extends keyof Cfg['resources']>(key: K, callback: (newValue: Cfg['resources'][K], oldValue: Cfg['resources'][K]) => void): () => void;
    /**
        * Whether a resource has active change subscribers.
        * Used by the system builder to skip caching for observed resources.
    */
    isResourceObserved<K extends keyof Cfg['resources']>(key: K): boolean;
    /**
        * Get all resource keys that are currently registered
        * @returns Array of resource keys
    */
    getResourceKeys(): Array<keyof Cfg['resources']>;
    /**
        * Check if a resource needs initialization (was added as a factory function)
        * @param key The resource key to check
        * @returns True if the resource needs initialization
    */
    resourceNeedsInitialization<K extends keyof Cfg['resources']>(key: K): boolean;
    /**
        * Get an entity by ID.
        * @param entityId The entity ID
        * @returns The entity, or undefined if it doesn't exist
    */
    getEntity(entityId: number): Entity<Cfg['components']> | undefined;
    /**
        * Get a component value from an entity.
        * @param entityId The entity ID
        * @param componentName The component to retrieve
        * @returns The component value, or undefined if the entity doesn't have it
    */
    getComponent<K extends keyof Cfg['components']>(entityId: number, componentName: K): Cfg['components'][K] | undefined;
    /**
        * Add or replace a component on an entity.
        * Triggers component-added callbacks and marks the component as changed.
        * @param entityId The entity ID
        * @param componentName The component to add
        * @param value The component value
    */
    addComponent<K extends keyof Cfg['components']>(entityId: number, componentName: K, value: Cfg['components'][K]): void;
    /**
        * Add multiple components to an entity at once.
        * @param entityId The entity ID
        * @param components Object with component names as keys and component data as values
    */
    addComponents<T extends {
        [K in keyof Cfg['components']]?: Cfg['components'][K];
    }>(entityId: number, components: T & Record<Exclude<keyof T, keyof Cfg['components']>, never>): void;
    /**
        * Remove a component from an entity.
        * Triggers component-removed and dispose callbacks.
        * @param entityId The entity ID
        * @param componentName The component to remove
    */
    removeComponent<K extends keyof Cfg['components']>(entityId: number, componentName: K): void;
    /**
        * Check if an entity has a component
    */
    hasComponent<K extends keyof Cfg['components']>(entityId: number, componentName: K): boolean;
    /**
        * Create an entity and add components to it in one call
        * @param components Object with component names as keys and component data as values
        * @returns The created entity with all components added
        */
    spawn<T extends {
        [K in keyof Cfg['components']]?: Cfg['components'][K];
    }>(components: T & Record<Exclude<keyof T, keyof Cfg['components']>, never>, options?: {
        scope?: (keyof Cfg['screens'] & string) | null;
    }): FilteredEntity<Cfg['components'], keyof T & keyof Cfg['components']>;
    /**
     * Read the active scope hint set by the current screen-gated system tick.
     * Returns `null` outside any system's process call, or when the active
     * system is not gated to the current screen.
     * @internal Used by CommandBuffer to capture intent at queue time.
     */
    _getActiveScopeHint(): (keyof Cfg['screens'] & string) | null;
    /**
     * Tag an entity as scoped to a screen.
     *
     * Scope resolution order:
     *   1. Explicit `options.scope === null` → unscoped (opt-out from hint).
     *   2. Explicit `options.scope: string` → scope to that screen.
     *   3. No `scope` provided (or `undefined`) → fall back to active hint set
     *      by the current screen-gated system tick. Otherwise unscoped.
     *
     * The entity is removed when its scoped screen exits.
     */
    private _applyScreenScope;
    /**
        * Get all entities with specific components
    */
    getEntitiesWithQuery<WithComponents extends keyof Cfg['components'], WithoutComponents extends keyof Cfg['components'] = never>(withComponents: ReadonlyArray<WithComponents>, withoutComponents?: ReadonlyArray<WithoutComponents>, changedComponents?: ReadonlyArray<keyof Cfg['components']>, parentHas?: ReadonlyArray<keyof Cfg['components']>): Array<FilteredEntity<Cfg['components'], WithComponents, WithoutComponents>>;
    /**
     * Get the single entity matching a query. Throws if zero or more than one match.
     * @param withComponents Components the entity must have
     * @param withoutComponents Components the entity must not have
     * @returns The single matching entity
     * @throws If zero or more than one entity matches
     */
    getSingleton<WithComponents extends keyof Cfg['components'], WithoutComponents extends keyof Cfg['components'] = never>(withComponents: ReadonlyArray<WithComponents>, withoutComponents?: ReadonlyArray<WithoutComponents>): FilteredEntity<Cfg['components'], WithComponents, WithoutComponents>;
    /**
     * Get the single entity matching a query, or undefined if none match.
     * Throws if more than one entity matches.
     * @param withComponents Components the entity must have
     * @param withoutComponents Components the entity must not have
     * @returns The single matching entity, or undefined if none match
     * @throws If more than one entity matches
     */
    tryGetSingleton<WithComponents extends keyof Cfg['components'], WithoutComponents extends keyof Cfg['components'] = never>(withComponents: ReadonlyArray<WithComponents>, withoutComponents?: ReadonlyArray<WithoutComponents>): FilteredEntity<Cfg['components'], WithComponents, WithoutComponents> | undefined;
    /**
     * Remove an entity (and optionally its descendants)
     * @param entityId Entity ID to remove
     * @param options Options for removal (cascade: true by default)
     * @returns true if entity was removed
     */
    removeEntity(entityId: number, options?: RemoveEntityOptions): boolean;
    /**
     * Create an entity as a child of another entity with initial components
     * @param parentId The parent entity ID
     * @param components Initial components to add
     * @returns The created child entity
     */
    spawnChild<T extends {
        [K in keyof Cfg['components']]?: Cfg['components'][K];
    }>(parentId: number, components: T & Record<Exclude<keyof T, keyof Cfg['components']>, never>, options?: {
        scope?: (keyof Cfg['screens'] & string) | null;
    }): FilteredEntity<Cfg['components'], keyof T & keyof Cfg['components']>;
    /**
     * Set the parent of an entity
     * @param childId The entity ID to set as a child
     * @param parentId The entity ID to set as the parent
     */
    setParent(childId: number, parentId: number): this;
    /**
     * Remove the parent relationship for an entity (orphan it)
     * @param childId The entity ID to orphan
     * @returns true if a parent was removed, false if entity had no parent
     */
    removeParent(childId: number): boolean;
    /**
     * Get the parent of an entity
     * @param entityId The entity ID to get the parent of
     * @returns The parent entity ID, or null if no parent
     */
    getParent(entityId: number): number | null;
    /**
     * Get all children of an entity in insertion order
     * @param parentId The parent entity ID
     * @returns Readonly array of child entity IDs
     */
    getChildren(parentId: number): readonly number[];
    /**
     * Get a child at a specific index
     * @param parentId The parent entity ID
     * @param index The index of the child
     * @returns The child entity ID, or null if index is out of bounds
     */
    getChildAt(parentId: number, index: number): number | null;
    /**
     * Get the index of a child within its parent's children list
     * @param parentId The parent entity ID
     * @param childId The child entity ID to find
     * @returns The index of the child, or -1 if not found
     */
    getChildIndex(parentId: number, childId: number): number;
    /**
     * Get all ancestors of an entity in order [parent, grandparent, ...]
     * @param entityId The entity ID to get ancestors of
     * @returns Readonly array of ancestor entity IDs
     */
    getAncestors(entityId: number): readonly number[];
    /**
     * Get all descendants of an entity in depth-first order
     * @param entityId The entity ID to get descendants of
     * @returns Readonly array of descendant entity IDs
     */
    getDescendants(entityId: number): readonly number[];
    /**
     * Get the root ancestor of an entity (topmost parent), or self if no parent
     * @param entityId The entity ID to get the root of
     * @returns The root entity ID
     */
    getRoot(entityId: number): number;
    /**
     * Get siblings of an entity (other children of the same parent)
     * @param entityId The entity ID to get siblings of
     * @returns Readonly array of sibling entity IDs
     */
    getSiblings(entityId: number): readonly number[];
    /**
     * Check if an entity is a descendant of another entity
     * @param entityId The potential descendant ID
     * @param ancestorId The potential ancestor ID
     * @returns true if entityId is a descendant of ancestorId
     */
    isDescendantOf(entityId: number, ancestorId: number): boolean;
    /**
     * Check if an entity is an ancestor of another entity
     * @param entityId The potential ancestor ID
     * @param descendantId The potential descendant ID
     * @returns true if entityId is an ancestor of descendantId
     */
    isAncestorOf(entityId: number, descendantId: number): boolean;
    /**
     * Get all root entities (entities that have children but no parent)
     * @returns Readonly array of root entity IDs
     */
    getRootEntities(): readonly number[];
    /**
     * Traverse the hierarchy in parent-first (breadth-first) order.
     * Parents are guaranteed to be visited before their children.
     * @param callback Function called for each entity with (entityId, parentId, depth)
     * @param options Optional traversal options (roots to filter to specific subtrees)
     */
    forEachInHierarchy(callback: (entityId: number, parentId: number | null, depth: number) => void, options?: HierarchyIteratorOptions): void;
    /**
     * Generator-based hierarchy traversal in parent-first (breadth-first) order.
     * Supports early termination via break.
     * @param options Optional traversal options (roots to filter to specific subtrees)
     * @yields HierarchyEntry for each entity in parent-first order
     */
    hierarchyIterator(options?: HierarchyIteratorOptions): Generator<HierarchyEntry, void, unknown>;
    /**
     * Emit a hierarchy changed event
     * @internal
     */
    private _emitHierarchyChanged;
    /**
        * Get all installed plugin IDs
    */
    get installedPlugins(): string[];
    get entityManager(): EntityManager<Cfg["components"]>;
    get eventBus(): EventBus<Cfg["events"]>;
    /**
     * Command buffer for queuing deferred structural changes.
     * Commands are executed automatically at the end of each update() cycle.
     *
     * @example
     * ```typescript
     * // In a system or event handler
     * ecs.commands.removeEntity(entityId);
     * ecs.commands.spawn({ position: { x: 0, y: 0 } });
     * ```
     */
    get commands(): CommandBuffer<Cfg>;
    /**
     * The current tick number, incremented at the end of each update()
     */
    get currentTick(): number;
    /**
     * The current change detection threshold.
     * During system execution, this is the system's last-seen sequence.
     * Between updates, this is the global sequence after command buffer playback.
     * Manual change detection should compare: getChangeSeq(...) > changeThreshold
     */
    get changeThreshold(): number;
    /**
     * Toggle diagnostics timing collection. When enabled, system and phase
     * timings are recorded each frame. When disabled, timing maps are cleared
     * and no overhead is incurred.
     */
    enableDiagnostics(enabled: boolean): void;
    get diagnosticsEnabled(): boolean;
    get systemTimings(): ReadonlyMap<string, number>;
    get phaseTimings(): Readonly<Record<SystemPhase, number>>;
    get entityCount(): number;
    /**
     * Mutate a component in place and automatically mark it as changed.
     * Throws if the entity does not exist or does not have the component.
     * @param entityId The entity ID
     * @param componentName The component to mutate
     * @param mutator A function that receives the component value for in-place mutation
     * @returns The mutated component value
     */
    mutateComponent<K extends keyof Cfg['components']>(entityId: number, componentName: K, mutator: (value: Cfg['components'][K]) => void): Cfg['components'][K];
    /**
     * Mark a component as changed on an entity. Recorded iff the component is
     * subscribed (auto-subscribed by any system's `changed:` filter, or implicit
     * track-all when no subscription exists). Each recorded call increments a
     * monotonic sequence; `changed:` queries see the mark once on their next run.
     */
    markChanged<K extends keyof Cfg['components']>(entityId: number, componentName: K): void;
    /**
     * Register a dispose callback for a component type.
     * Called when a component is removed (explicit removal, entity destruction, or replacement).
     * Later registrations replace earlier ones for the same component type.
     * @param componentName The component type to register disposal for
     * @param callback Function receiving the component value being disposed and the entity ID
     */
    registerDispose<K extends keyof Cfg['components']>(componentName: K, callback: (ctx: {
        value: Cfg['components'][K];
        entityId: number;
    }) => void): void;
    /**
     * Register a required component relationship.
     * When an entity gains `trigger`, the `required` component is auto-added
     * (using `factory` for the default value) if not already present.
     * Enforced at insertion time (spawn/addComponent) only — removal is unrestricted.
     * @param trigger The component whose presence triggers auto-addition
     * @param required The component to auto-add
     * @param factory Function that creates the default value for the required component
     */
    registerRequired<Trigger extends keyof Cfg['components'], Required extends keyof Cfg['components']>(trigger: Trigger, required: Required, factory: (triggerValue: Cfg['components'][Trigger]) => Cfg['components'][Required]): void;
    /**
     * Check for circular dependencies in the required components graph.
     * @throws Error if adding trigger→newRequired would create a cycle
     */
    private _checkRequiredCycle;
    /**
     * Register a callback when a specific component is added to any entity
     * @param componentName The component key
     * @param handler Function receiving the new component value and the entity
     * @returns Unsubscribe function to remove the callback
     */
    onComponentAdded<K extends keyof Cfg['components']>(componentName: K, handler: (ctx: {
        value: Cfg['components'][K];
        entity: Entity<Cfg['components']>;
    }) => void): () => void;
    /**
     * Register a callback when a specific component is removed from any entity
     * @param componentName The component key
     * @param handler Function receiving the old component value and the entity
     * @returns Unsubscribe function to remove the callback
     */
    onComponentRemoved<K extends keyof Cfg['components']>(componentName: K, handler: (ctx: {
        value: Cfg['components'][K];
        entity: Entity<Cfg['components']>;
    }) => void): () => void;
    /**
     * Add a reactive query that triggers callbacks when entities enter/exit the query match.
     * @param name Unique name for the query
     * @param definition Query definition with with/without arrays and onEnter/onExit callbacks
     */
    addReactiveQuery<WithComponents extends keyof Cfg['components'], WithoutComponents extends keyof Cfg['components'] = never, OptionalComponents extends keyof Cfg['components'] = never>(name: ReactiveQueryNames, definition: ReactiveQueryDefinition<Cfg['components'], WithComponents, WithoutComponents, OptionalComponents>): void;
    /**
     * Remove a reactive query by name.
     * @param name Name of the query to remove
     * @returns true if the query existed and was removed, false otherwise
     */
    removeReactiveQuery(name: ReactiveQueryNames): boolean;
    /**
     * Subscribe to an event (convenience wrapper for eventBus.subscribe)
     * @param eventType The event type to subscribe to
     * @param callback The callback to invoke when the event is published
     * @returns An unsubscribe function
     */
    on<E extends keyof Cfg['events']>(eventType: E, callback: (data: Cfg['events'][E]) => void): () => void;
    /**
     * Unsubscribe from an event by callback reference (convenience wrapper for eventBus.unsubscribe)
     * @param eventType The event type to unsubscribe from
     * @param callback The callback to remove
     * @returns true if the callback was found and removed, false otherwise
     */
    off<E extends keyof Cfg['events']>(eventType: E, callback: (data: Cfg['events'][E]) => void): boolean;
    /**
     * Register a hook that runs after all systems in update()
     * @param callback The hook to call after all systems have processed
     * @returns An unsubscribe function to remove the hook
     */
    onPostUpdate(callback: (ctx: {
        ecs: ECSpresso<Cfg>;
        dt: number;
    }) => void): () => void;
    private requireAssetManager;
    /**
     * Get a loaded asset by key. Throws if not loaded.
     */
    getAsset<K extends keyof Cfg['assets']>(key: K): Cfg['assets'][K];
    /**
     * Get a loaded asset or undefined if not loaded
     */
    tryGetAsset<K extends keyof Cfg['assets']>(key: K): Cfg['assets'][K] | undefined;
    /**
     * Get a handle to an asset with status information
     */
    getAssetHandle<K extends keyof Cfg['assets']>(key: K): AssetHandle<Cfg['assets'][K]>;
    /**
     * Check if an asset is loaded
     */
    isAssetLoaded<K extends keyof Cfg['assets']>(key: K): boolean;
    /**
     * Load a single asset
     */
    loadAsset<K extends keyof Cfg['assets']>(key: K): Promise<Cfg['assets'][K]>;
    /**
     * Load all assets in a group
     */
    loadAssetGroup(groupName: AssetGroupNames): Promise<void>;
    /**
     * Check if all assets in a group are loaded
     */
    isAssetGroupLoaded(groupName: AssetGroupNames): boolean;
    /**
     * Get the loading progress of a group (0-1)
     */
    getAssetGroupProgress(groupName: AssetGroupNames): number;
    private requireScreenManager;
    /**
     * Transition to a new screen, clearing the stack
     */
    setScreen<K extends keyof Cfg['screens']>(name: K, config: Cfg['screens'][K] extends ScreenDefinition<infer C, any> ? C : never): Promise<void>;
    /**
     * Push a screen onto the stack (overlay)
     */
    pushScreen<K extends keyof Cfg['screens']>(name: K, config: Cfg['screens'][K] extends ScreenDefinition<infer C, any> ? C : never): Promise<void>;
    /**
     * Pop the current screen and return to the previous one
     */
    popScreen(): Promise<void>;
    /**
     * Get the current screen name
     */
    getCurrentScreen(): keyof Cfg['screens'] | null;
    /**
     * Get the current screen config (immutable), narrowed to a specific screen.
     * Throws if the current screen doesn't match.
     */
    getScreenConfig<K extends keyof Cfg['screens'] & string>(screen: K): Cfg['screens'][K] extends ScreenDefinition<infer C, any> ? Readonly<C> : never;
    /**
     * Get the current screen config (immutable).
     * Returns a union of all possible config types.
     */
    getScreenConfig(): {
        [K in keyof Cfg['screens']]: Cfg['screens'][K] extends ScreenDefinition<infer C, any> ? Readonly<C> : never;
    }[keyof Cfg['screens']];
    /**
     * Get the current screen config narrowed to a specific screen, or undefined if not on that screen.
     */
    tryGetScreenConfig<K extends keyof Cfg['screens'] & string>(screen: K): (Cfg['screens'][K] extends ScreenDefinition<infer C, any> ? Readonly<C> : never) | undefined;
    /**
     * Get the current screen config or undefined.
     * Returns a union of all possible config types, or undefined.
     */
    tryGetScreenConfig(): {
        [K in keyof Cfg['screens']]: Cfg['screens'][K] extends ScreenDefinition<infer C, any> ? Readonly<C> : never;
    }[keyof Cfg['screens']] | undefined;
    /**
     * Get the current screen state (mutable), narrowed to a specific screen.
     * Throws if the current screen doesn't match.
     */
    getScreenState<K extends keyof Cfg['screens'] & string>(screen: K): Cfg['screens'][K] extends ScreenDefinition<any, infer S> ? S : never;
    /**
     * Get the current screen state (mutable).
     * Returns a union of all possible state types.
     */
    getScreenState(): {
        [K in keyof Cfg['screens']]: Cfg['screens'][K] extends ScreenDefinition<any, infer S> ? S : never;
    }[keyof Cfg['screens']];
    /**
     * Get the current screen state narrowed to a specific screen, or undefined if not on that screen.
     */
    tryGetScreenState<K extends keyof Cfg['screens'] & string>(screen: K): (Cfg['screens'][K] extends ScreenDefinition<any, infer S> ? S : never) | undefined;
    /**
     * Get the current screen state or undefined.
     * Returns a union of all possible state types, or undefined.
     */
    tryGetScreenState(): {
        [K in keyof Cfg['screens']]: Cfg['screens'][K] extends ScreenDefinition<any, infer S> ? S : never;
    }[keyof Cfg['screens']] | undefined;
    /**
     * Update the current screen state, narrowed to a specific screen.
     * Throws if the current screen doesn't match.
     */
    updateScreenState<K extends keyof Cfg['screens'] & string>(screen: K, update: Partial<Cfg['screens'][K] extends ScreenDefinition<any, infer S> ? S : never> | ((current: Cfg['screens'][K] extends ScreenDefinition<any, infer S> ? S : never) => Partial<Cfg['screens'][K] extends ScreenDefinition<any, infer S> ? S : never>)): void;
    /**
     * Update the current screen state.
     */
    updateScreenState<K extends keyof Cfg['screens']>(update: Partial<Cfg['screens'][K] extends ScreenDefinition<any, infer S> ? S : never> | ((current: Cfg['screens'][K] extends ScreenDefinition<any, infer S> ? S : never) => Partial<Cfg['screens'][K] extends ScreenDefinition<any, infer S> ? S : never>)): void;
    /**
     * Check if a screen is the current screen
     */
    isCurrentScreen(screenName: keyof Cfg['screens']): boolean;
    /**
     * Check if a screen is active (current or in stack)
     */
    isScreenActive(screenName: keyof Cfg['screens']): boolean;
    /**
     * Get the screen stack depth
     */
    getScreenStackDepth(): number;
    /**
     * Subscribe to the `screenEnter` event for a specific screen. The handler
     * fires only when that named screen becomes active (via `setScreen` or
     * `pushScreen`). Multiple handlers can be registered for the same screen
     * and fire in registration order.
     *
     * @returns A disposer function that unregisters the handler.
     */
    onScreenEnter<K extends keyof Cfg['screens'] & string>(name: K, handler: (ctx: {
        config: Cfg['screens'][K] extends ScreenDefinition<infer C, any> ? C : never;
        ecs: ECSpresso<Cfg>;
    }) => void): () => void;
    /**
     * Subscribe to the `screenExit` event for a specific screen. The handler
     * fires only when that named screen exits (via `setScreen` away, or
     * `popScreen` if it was on the stack). Multiple handlers can be registered
     * for the same screen and fire in registration order.
     *
     * @returns A disposer function that unregisters the handler.
     */
    onScreenExit<K extends keyof Cfg['screens'] & string>(name: K, handler: (ctx: {
        ecs: ECSpresso<Cfg>;
    }) => void): () => void;
    /**
     * Internal method to set the asset manager and drain pending plugin assets
     * @internal Used by ECSpressoBuilder
     */
    _setAssetManager(manager: AssetManager<Cfg['assets']>): void;
    /**
     * Internal method to set the screen manager and drain pending plugin screens
     * @internal Used by ECSpressoBuilder
     */
    _setScreenManager(manager: ScreenManager<Cfg['screens']>): void;
    /** @internal */
    _hasPendingPluginAssets(): boolean;
    /** @internal */
    _hasPendingPluginScreens(): boolean;
    /**
     * Internal method to set the fixed timestep interval
     * @internal Used by ECSpressoBuilder
     */
    _setFixedDt(dt: number): void;
    /**
     * Register an asset definition for deferred registration.
     * @internal Used by plugins that need to register assets
     */
    _registerAsset(key: string, definition: AssetDefinition<unknown>): void;
    /**
     * Register a screen definition for deferred registration.
     * @internal Used by plugins that need to register screens
     */
    _registerScreen(name: string, definition: ScreenDefinition<any, any>): void;
    /**
     * Install a plugin into this ECSpresso instance.
     * Deduplicates by plugin ID. Composite plugins call this in their install function.
     *
     * The overload enforces that the plugin's provided config is compatible with
     * this world's accumulated config, and that its required config is satisfied.
     * When a check fails the parameter resolves to a `PluginError<...>` sentinel
     * whose template-literal message names the failing WorldConfig slot, making
     * the resulting "not assignable" error self-describing.
     */
    installPlugin<PCfg extends WorldConfig, PReq extends WorldConfig = EmptyConfig, BL extends string = never, BG extends string = never, BAG extends string = never, BRQ extends string = never>(plugin: InstallPluginParam<Cfg, PCfg, PReq, BL, BG, BAG, BRQ>): this;
    /**
     * Install a plugin without enforcing compatibility constraints.
     * @internal Used by the builder, which has already validated compatibility
     * at `withPlugin` time via the builder's own constrained overload.
     */
    _installPluginUnchecked(plugin: Plugin<WorldConfig, WorldConfig, string, string, string, string>): this;
    /**
     * Uninstall a previously installed plugin by id. Runs registered cleanup
     * disposers in reverse order and removes the plugin from `installedPlugins`.
     * Returns `true` if the plugin was installed (and has now been removed),
     * `false` if no plugin with that id was installed.
     *
     * Disposers that throw are caught and logged via `console.warn` so a single
     * failing disposer does not prevent later ones from running.
     */
    uninstallPlugin(id: string): boolean;
    /**
     * Uninstall every installed plugin, running their cleanup disposers.
     * Plugins are uninstalled in reverse install order so a plugin that depends
     * on another is torn down before its dependency.
     *
     * Does not touch resource disposal — callers that need async resource
     * teardown should `await world.disposeResources()` separately.
     */
    dispose(): void;
    /**
     * Create a plugin factory from the built world's types.
     * Returns a definePlugin equivalent with no manual type parameters.
     */
    pluginFactory(): <PL extends string = never, PG extends string = never, PAG extends string = never, PRQ extends string = never>(config: {
        id: string;
        install: (world: ECSpresso<Cfg>) => void;
    }) => Plugin<Cfg, EmptyConfig, PL, PG, PAG, PRQ>;
    /**
     * Call a helper factory with this world instance, inferring the full world type.
     * Eliminates the need for a separate `type ECS = typeof ecs` ceremony.
     *
     * @example
     * ```typescript
     * const helpers = ecs.getHelpers(createStateMachineHelpers);
     * ```
     */
    getHelpers<H>(factory: (world: this) => H): H;
}
export {};
