import ECSpresso from "./ecspresso";
import type { WorldConfig, EmptyConfig, WorldConfigFrom } from "./type-utils";
/**
 * Execution phase for systems. Systems are grouped by phase and executed
 * in this fixed order: preUpdate -> fixedUpdate -> update -> postUpdate -> render.
 * Within each phase, systems are sorted by priority (higher first).
 */
export type SystemPhase = 'preUpdate' | 'fixedUpdate' | 'update' | 'postUpdate' | 'render';
export interface Entity<ComponentTypes> {
    id: number;
    components: Partial<ComponentTypes>;
}
/**
 * Options for removing an entity
 */
export interface RemoveEntityOptions {
    /**
     * Whether to also remove all descendants (default: true)
     */
    cascade?: boolean;
}
/**
 * Options for hierarchy traversal methods
 */
export interface HierarchyIteratorOptions {
    /** Specific root entities to start traversal from. If not provided, all root entities are used. */
    roots?: readonly number[];
}
/**
 * Entry yielded during hierarchy traversal
 */
export interface HierarchyEntry {
    /** The entity being visited */
    entityId: number;
    /** The parent entity ID, or null for root entities */
    parentId: number | null;
    /** Depth in the hierarchy (0 for roots) */
    depth: number;
}
export interface FilteredEntity<ComponentTypes, WithComponents extends keyof ComponentTypes = never, WithoutComponents extends keyof ComponentTypes = never, OptionalComponents extends keyof ComponentTypes = never, MutatesComponents extends keyof ComponentTypes = keyof ComponentTypes> {
    id: number;
    components: Omit<Partial<ComponentTypes>, WithComponents | WithoutComponents | OptionalComponents> & {
        [K in WithComponents]: K extends MutatesComponents ? ComponentTypes[K] : Readonly<ComponentTypes[K]>;
    } & {
        [K in OptionalComponents]: ComponentTypes[K] | undefined;
    };
}
export interface QueryConfig<ComponentTypes, WithComponents extends keyof ComponentTypes, WithoutComponents extends keyof ComponentTypes, OptionalComponents extends keyof ComponentTypes = WithComponents, MutatesComponents extends keyof ComponentTypes = keyof ComponentTypes> {
    with: ReadonlyArray<WithComponents>;
    without?: ReadonlyArray<WithoutComponents>;
    changed?: ReadonlyArray<WithComponents>;
    optional?: ReadonlyArray<OptionalComponents>;
    parentHas?: ReadonlyArray<keyof ComponentTypes>;
    /**
     * Components to auto-mark as changed on every iterated entity after
     * `process()` returns. Eliminates repeated `ecs.markChanged(id, name)`
     * boilerplate inside iteration loops. Components listed in `with` but
     * absent from `mutates` are narrowed to `Readonly<T>` on the iteration
     * entity, catching accidental writes at compile time.
     */
    mutates?: ReadonlyArray<MutatesComponents>;
    /** @internal Pre-resolved component indices for `changed:`, populated at system registration. */
    _changedIdx?: ReadonlyArray<number>;
    /** @internal Pre-resolved component indices for `mutates:`, populated at system registration. */
    _mutatesIdx?: ReadonlyArray<number>;
}
/**
 * Utility type to derive the entity type that would result from a query definition.
 * This is useful for creating helper functions that operate on query results.
 *
 * @example
 * ```typescript
 * const queryDef = {
 *   with: ['position', 'sprite'],
 *   without: ['dead']
 * };
 *
 * type EntityType = QueryResultEntity<Components, typeof queryDef>;
 *
 * function updateSpritePosition(entity: EntityType) {
 *   entity.components.sprite.position.set(
 *     entity.components.position.x,
 *     entity.components.position.y
 *   );
 * }
 * ```
 */
export type QueryResultEntity<ComponentTypes extends Record<string, any>, QueryDef extends {
    with: ReadonlyArray<keyof ComponentTypes>;
    without?: ReadonlyArray<keyof ComponentTypes>;
    changed?: ReadonlyArray<keyof ComponentTypes>;
    optional?: ReadonlyArray<keyof ComponentTypes>;
    parentHas?: ReadonlyArray<keyof ComponentTypes>;
    mutates?: ReadonlyArray<keyof ComponentTypes>;
}> = FilteredEntity<ComponentTypes, QueryDef['with'][number], QueryDef['without'] extends ReadonlyArray<any> ? QueryDef['without'][number] : never, QueryDef['optional'] extends ReadonlyArray<any> ? QueryDef['optional'][number] : never, QueryDef['mutates'] extends ReadonlyArray<any> ? QueryDef['mutates'][number] : QueryDef['with'][number]>;
/**
 * Simplified query definition type for creating reusable queries
 */
export type QueryDefinition<ComponentTypes extends Record<string, any>, WithComponents extends keyof ComponentTypes = keyof ComponentTypes, WithoutComponents extends keyof ComponentTypes = keyof ComponentTypes, OptionalComponents extends keyof ComponentTypes = keyof ComponentTypes, MutatesComponents extends keyof ComponentTypes = keyof ComponentTypes> = {
    with: ReadonlyArray<WithComponents>;
    without?: ReadonlyArray<WithoutComponents>;
    changed?: ReadonlyArray<WithComponents>;
    optional?: ReadonlyArray<OptionalComponents>;
    parentHas?: ReadonlyArray<keyof ComponentTypes>;
    /**
     * Components to auto-mark as changed on every iterated entity after
     * `process()` returns. Components in `with` but absent from `mutates`
     * are narrowed to `Readonly<T>` on the iteration entity type.
     */
    mutates?: ReadonlyArray<MutatesComponents>;
    /** @internal Pre-resolved component indices for `changed:`, populated at system registration. */
    _changedIdx?: ReadonlyArray<number>;
    /** @internal Pre-resolved component indices for `mutates:`, populated at system registration. */
    _mutatesIdx?: ReadonlyArray<number>;
};
/**
 * Helper function to create a query definition with proper type inference.
 * This enables better TypeScript inference when creating reusable queries.
 *
 * @example
 * ```typescript
 * const movingEntitiesQuery = createQueryDefinition({
 *   with: ['position', 'velocity'],
 *   without: ['dead']
 * });
 *
 * type MovingEntity = QueryResultEntity<Components, typeof movingEntitiesQuery>;
 *
 * function updatePosition(entity: MovingEntity) {
 *   entity.components.position.x += entity.components.velocity.x;
 *   entity.components.position.y += entity.components.velocity.y;
 * }
 *
 * world.addSystem('movement')
 *   .addQuery('entities', movingEntitiesQuery)
 *   .setProcess(({ queries }) => {
 *     for (const entity of queries.entities) {
 *       updatePosition(entity);
 *     }
 *   });
 * ```
 */
export declare function createQueryDefinition<ComponentTypes extends Record<string, any>, const QueryDef extends {
    with: ReadonlyArray<keyof ComponentTypes>;
    without?: ReadonlyArray<keyof ComponentTypes>;
    changed?: ReadonlyArray<keyof ComponentTypes>;
    optional?: ReadonlyArray<keyof ComponentTypes>;
    parentHas?: ReadonlyArray<keyof ComponentTypes>;
    mutates?: ReadonlyArray<keyof ComponentTypes>;
}>(queryDef: QueryDef): QueryDef;
export interface System<Cfg extends WorldConfig = EmptyConfig, WithComponents extends keyof Cfg['components'] = never, WithoutComponents extends keyof Cfg['components'] = never> {
    label: string;
    /**
     * System priority - higher values execute first (default: 0)
     * When systems have the same priority, they execute in registration order
     */
    priority?: number;
    /**
     * Execution phase for this system (default: 'update')
     * Systems are grouped by phase and executed in order:
     * preUpdate -> fixedUpdate -> update -> postUpdate -> render
     */
    phase?: SystemPhase;
    /**
     * Groups this system belongs to. If any group is disabled, the system will be skipped.
     */
    groups?: string[];
    /**
     * Screens where this system should run. If specified, system only runs
     * when current screen is in this list.
     */
    inScreens?: ReadonlyArray<keyof Cfg['screens'] & string>;
    /**
     * Screens where this system should NOT run. If specified, system skips
     * when current screen is in this list.
     */
    excludeScreens?: ReadonlyArray<keyof Cfg['screens'] & string>;
    /**
     * Assets that must be loaded for this system to run.
     * System will be skipped if any required asset is not loaded.
     */
    requiredAssets?: ReadonlyArray<keyof Cfg['assets'] & string>;
    /**
     * When true, the system's process function runs even when all queries
     * return zero entities. Default is false (system is skipped when all
     * queries are empty).
     */
    runWhenEmpty?: boolean;
    entityQueries?: {
        [queryName: string]: QueryConfig<Cfg['components'], WithComponents, WithoutComponents>;
    };
    /**
     * Singleton queries that yield a single entity (or undefined) rather than
     * an array. Resolved into the process context's `queries` object under
     * the registered name.
     */
    entitySingletons?: {
        [singletonName: string]: QueryConfig<Cfg['components'], WithComponents, WithoutComponents>;
    };
    /**
     * Process method that runs during each update cycle.
     * Receives a single context object with queries, dt, and ecs.
     */
    process?(ctx: {
        queries: {
            [queryName: string]: Array<FilteredEntity<Cfg['components'], WithComponents, WithoutComponents>>;
        };
        dt: number;
        ecs: ECSpresso<Cfg>;
    }): void;
    /**
     * Lifecycle hook called when the system is initialized
     * This is called when ECSpresso.initialize() is invoked, after resources are initialized
     * Use this for one-time initialization that depends on resources
     * @param ecs The ECSpresso instance providing access to all ECS functionality
     */
    onInitialize?(ecs: ECSpresso<Cfg>): void | Promise<void>;
    /**
     * Lifecycle hook called when the system is detached from the ECS
     * @param ecs The ECSpresso instance providing access to all ECS functionality
     */
    onDetach?(ecs: import("./ecspresso").default<Cfg>): void;
    /**
     * Per-query callbacks that fire once per entity the first time it appears
     * in a query's results. Fires before process. Automatic cleanup when
     * entity leaves query (component removed, entity destroyed) so re-entry
     * fires the callback again.
     */
    onEntityEnter?: Record<string, (ctx: {
        entity: FilteredEntity<Cfg['components'], WithComponents, WithoutComponents>;
        ecs: ECSpresso<Cfg>;
    }) => void>;
    /**
     * Event handlers for specific event types
     */
    eventHandlers?: {
        [EventName in keyof Cfg['events']]?: (ctx: {
            data: Cfg['events'][EventName];
            ecs: ECSpresso<Cfg>;
        }) => void;
    };
    /**
     * @internal Precomputed pairs of (queryName, mutates, kind) derived at
     * system registration from queries/singletons declaring `mutates`. Null
     * when no query on the system declares `mutates`, so the post-process
     * auto-mark walk is a single pointer check away from zero cost for
     * non-users.
     */
    _autoMarkPairs?: ReadonlyArray<{
        queryName: string;
        mutatesIdx: ReadonlyArray<number>;
        kind: 'list' | 'singleton';
    }> | null;
}
/**
 * Typed world interface for plugin helpers and structural typing.
 *
 * Generic over component types `C`:
 * - `BaseWorld` (no param): defaults to `{}`, meaning component-accessing methods
 *   cannot be called (keys resolve to `never`). Use for functions that only need
 *   `removeEntity`, `getResource`, etc.
 * - `BaseWorld<MyComponents>`: narrows `getComponent`, `hasComponent`, `markChanged`,
 *   `spawn`, and command buffer methods to the declared component map.
 *
 * Structural typing ensures any `ECSpresso<Cfg>` where `Cfg['components']` is a
 * superset of `C` satisfies `BaseWorld<C>`.
 */
type _BaseWorldCfg<C extends Record<string, any>> = WorldConfigFrom<C, Record<string, any>, Record<string, any>, Record<string, unknown>, Record<string, any>>;
type _EventBus = import("./event-bus").default<Record<string, any>>;
export type BaseWorld<C extends Record<string, any> = {}> = Pick<ECSpresso<_BaseWorldCfg<C>>, 'getComponent' | 'hasComponent' | 'removeEntity' | 'spawn' | 'markChanged' | 'getResource' | 'hasResource'> & {
    eventBus: Pick<_EventBus, 'publish'>;
    commands: Pick<import("./command-buffer").default<_BaseWorldCfg<C>>, 'spawn' | 'removeEntity' | 'addComponent' | 'removeComponent'>;
};
export type { Merge, MergeAll, TypesAreCompatible, ComponentsOf, EventsOf, ResourcesOf, LabelsOf, GroupsOf, AssetGroupNamesOf, ReactiveQueryNamesOf, AssetTypesOf, ScreenStatesOf, ComponentsOfWorld, EventsOfWorld, AssetsOfWorld, ScreenStatesOfWorld, AnyECSpresso, AnyPlugin, EventNameMatching, ChannelOfWorld, WorldConfig, EmptyConfig, WorldConfigFrom, ComponentsConfig, EventsConfig, ResourcesConfig, AssetsConfig, ScreensConfig, MergeConfigs, ConfigsAreCompatible, ConfigOf, WithComponents, WithEvents, WithResources, WithAssets, WithScreens } from './type-utils';
