import { Bucket } from "@miniplex/bucket";
export * from "@miniplex/bucket";
export type Predicate<E, D extends E> = ((v: E) => v is D) | ((entity: E) => boolean);
/**
 * A utility type that marks the specified properties as required.
 */
export type With<E, P extends keyof E> = E & Required<Pick<E, P>>;
export type Without<E, P extends keyof E> = Omit<E, P>;
/**
 * A utility type that removes all optional properties.
 */
export type Strict<T> = WithoutOptional<T>;
type OptionalKeys<T> = {
    [K in keyof T]-?: undefined extends T[K] ? K : never;
};
type WithoutOptional<T> = Pick<T, Exclude<keyof T, OptionalKeys<T>[keyof T]>>;
type QueryConfiguration = {
    with: any[];
    without: any[];
    predicates: Function[];
};
interface IQueryableBucket<E> {
    /**
     * Queries for entities that have all of the given components. If this is called on
     * an existing query, the query will be extended to include this new criterion.
     *
     * @param components The components to query for.
     */
    with<C extends keyof E>(...components: C[]): Query<With<E, C>>;
    /**
     * Queries for entities that have none of the given components. If this is called on
     * an existing query, the query will be extended to include this new criterion.
     *
     * @param components The components to query for.
     */
    without<C extends keyof E>(...components: C[]): Query<Without<E, C>>;
    /**
     * Queries for entities that match the given predicate. If this is called on
     * an existing query, the query will be extended to include this new criterion.
     *
     * @param predicate The predicate to query for.
     */
    where<D extends E>(predicate: Predicate<E, D>): Query<D>;
}
export declare class World<E extends {} = any> extends Bucket<E> implements IQueryableBucket<E> {
    constructor(entities?: E[]);
    update(entity: E): E;
    update<C extends keyof E>(entity: E, component: C, value: E[C]): E;
    update(entity: E, update: Partial<E>): E;
    update(entity: E, fun: (entity: E) => Partial<E> | void): E;
    /**
     * Adds a component to an entity. If the entity already has the component, the
     * existing component will not be overwritten.
     *
     * After the component was added, the entity will be reindexed, causing it to be
     * added to or removed from any queries depending on their criteria.
     *
     * @param entity The entity to modify.
     * @param component The name of the component to add.
     * @param value The value of the component to add.
     */
    addComponent<C extends keyof E>(entity: E, component: C, value: E[C]): void;
    /**
     * Removes a component from an entity. If the entity does not have the component,
     * this function does nothing.
     *
     * After the component was removed, the entity will be reindexed, causing it to be
     * added to or removed from any queries depending on their criteria.
     *
     * @param entity The entity to modify.
     * @param component The name of the component to remove.
     */
    removeComponent(entity: E, component: keyof E): void;
    protected queries: Set<Query<any>>;
    /**
     * Creates (or reuses) a query that matches the given configuration.
     *
     * @param config The query configuration.
     * @returns A query that matches the given configuration.
     */
    query<D>(config: QueryConfiguration): Query<D>;
    /**
     * Creates (or reuses) a query that holds entities that have all of the specified
     * components.
     *
     * @param components One or more component names to query for.
     * @returns A query that holds entities that have all of the given components.
     */
    with<C extends keyof E>(...components: C[]): Query<With<E, C>>;
    /**
     * Creates (or reuses) a query that holds entities that do not have any of the
     * specified components.
     *
     * @param components One or more component names to query for.
     * @returns A query that holds entities that do not have any of the given components.
     */
    without<C extends keyof E>(...components: C[]): Query<Without<E, C>>;
    /**
     * Creates (or reuses) a query that holds entities that match the given predicate.
     * Please note that as soon as you are building queries that use predicates, you
     * will need to explicitly reindex entities when their properties change.
     *
     * @param predicate The predicate that entities must match.
     * @returns A query that holds entities that match the given predicate.
     */
    where<D extends E>(predicate: Predicate<E, D>): Query<D>;
    /**
     * Reindexes the specified entity. This will iteratere over all registered queries
     * and ask them to reevaluate the entity.
     *
     * If the `future` parameter is specified,
     * it will be used in the evaluation instead of the entity itself. This is useful
     * if you are about to perform a destructive change on the entity (like removing
     * a component), but want emitted events to still have access to the unmodified entity
     * before the change.
     *
     * @param entity The entity to reindex.
     * @param future The entity that the entity will become in the future.
     */
    reindex(entity: E, future?: E): void;
    private entityToId;
    private idToEntity;
    private nextId;
    /**
     * Generate and return a numerical identifier for the given entity. The ID can later
     * be used to retrieve the entity again through the `entity(id)` method.
     *
     * @param entity The entity to get the ID for.
     * @returns An ID for the entity, or undefined if the entity is not in the world.
     */
    id(entity: E): number | undefined;
    /**
     * Given an entity ID that was previously generated through the `id(entity)` function,
     * returns the entity matching that ID, or undefined if no such entity exists.
     *
     * @param id The ID of the entity to retrieve.
     * @returns The entity with the given ID, or undefined if no such entity exists.
     */
    entity(id: number): E | undefined;
}
export declare class Query<E> extends Bucket<E> implements IQueryableBucket<E> {
    world: World;
    config: QueryConfiguration;
    protected _isConnected: boolean;
    /**
     * True if this query is connected to the world, and will automatically
     * re-evaluate when entities are added or removed.
     */
    get isConnected(): boolean;
    /**
     * A unique, string-based key for this query, based on its configuration.
     */
    readonly key: string;
    constructor(world: World, config: QueryConfiguration);
    /**
     * An array containing all entities that match this query. For iteration, it
     * is recommended to use the `for (const entity of query) {}` syntax instead.
     */
    get entities(): E[];
    [Symbol.iterator](): {
        next: () => {
            value: E;
            done: boolean;
        };
    };
    /**
     * Connects this query to the world. While connected, it will automatically
     * re-evaluate when entities are added or removed, and store those that match
     * its query configuration.
     *
     * @returns The query object.
     */
    connect(): this;
    /**
     * Disconnects this query from the world. This essentially stops the query from
     * automatically receiving entities.
     */
    disconnect(): this;
    /**
     * Returns a new query that extends this query and also matches entities that
     * have all of the components specified.
     *
     * @param components The components that entities must have.
     * @returns A new query representing the extended query configuration.
     */
    with<C extends keyof E>(...components: C[]): Query<With<E, C>>;
    /**
     * Returns a new query that extends this query and also matches entities that
     * have none of the components specified.
     *
     * @param components The components that entities must not have.
     * @returns A new query representing the extended query configuration.
     */
    without<C extends keyof E>(...components: C[]): Query<Without<E, C>>;
    /**
     * Returns a new query that extends this query and also matches entities that
     * match the given predicate.
     *
     * @param predicate The predicate that entities must match.
     * @returns A new query representing the extended query configuration.
     */
    where<D extends E>(predicate: Predicate<E, D>): Query<D>;
    /**
     * Checks the given entity against this query's configuration, and returns
     * true if the entity matches the query, false otherwise.
     *
     * @param entity The entity to check.
     * @returns True if the entity matches this query, false otherwise.
     */
    want(entity: E): boolean;
    /**
     * Evaluate the given entity against this query's configuration, and add or
     * remove it from the query if necessary.
     *
     * If `future` is specified, the entity will be evaluated against that entity
     * instead. This is useful for checking if an entity will match the query
     * after some potentially destructive change has been made to it, before
     * actually applying that change to the entity itself.
     *
     * @param entity The entity to evaluate.
     * @param future The entity to evaluate against. If not specified, the entity will be evaluated against itself.
     */
    evaluate(entity: any, future?: any): void;
}
