import { type AnyObject, type ArrayElement, type Values } from '@augment-vir/common';
import { type ShapeDefinition } from 'object-shape-tester';
import { type Constructor } from 'type-fest';
import { BaseEntity, type EntityDestroyEvent, EntityStore, type EntityStoreConstructorParams, type ParamsMap, type ReverseParamsMap, ViewEntity } from './entity.js';
/**
 * Params for both {@link EntitySuite.defineEntity} and {@link EntitySuite.defineLogicEntity}.
 *
 * @category Internal
 */
export type DefineEntityParams<EntityKey extends string, Shape extends ShapeDefinition<AnyObject, any> | undefined, Events extends ReadonlyArray<Constructor<Event>> = never> = {
    /**
     * This key is used for deserialization of entities to track which class needs to be
     * constructed. Do not use duplicate key strings across multiple entity classes.
     */
    key: EntityKey;
    /**
     * This should contain all parameters necessary to reconstruct this entity from scratch so it
     * can be serialized, sent across the network in JSON format, then reconstructed on another
     * device (for multiplayer support).
     *
     * Make sure to include {@link entityPositionParamsShape} if you want to include the base entity
     * position parameters.
     */
    paramsShape: Shape;
    /**
     * All events that this entity can emit, in addition to the default {@link EntityDestroyEvent}
     * event.
     */
    events?: Events | undefined;
    /**
     * A mapping of the entity's params object (defined by {@link DefineEntityParams.paramsShape})
     * keys to hitbox and/or view properties.
     *
     * @default undefined // no mapping
     */
    paramsMap?: ParamsMap<Shape extends ShapeDefinition<AnyObject, any> ? Shape['runtimeType'] : undefined> | undefined;
};
/**
 * Static members of both view and logic entity constructors.
 *
 * @category Internal
 */
export type StaticEntity<EntityKey, Shape extends ShapeDefinition<AnyObject, any> | undefined> = {
    /**
     * This key is used for deserialization of entities to track which class needs to be
     * constructed. You cannot have duplicate keys loaded at the same time.
     */
    entityKey: EntityKey;
    /** Shape definition of this entity's parameters. */
    paramsShape: Shape;
    /**
     * Defines which properties from {@link BaseEntity.params} will be mapped to hitbox and/or view
     * properties.
     */
    paramsMap: ParamsMap<Shape extends ShapeDefinition<AnyObject, any> ? Shape['runtimeType'] : undefined>;
    /** Parses the serialized params generated by {@link BaseEntity.serialize}. */
    deserialize(serialized: string | undefined): AnyObject | undefined;
};
/**
 * ========================
 *
 * # View Entity
 *
 * Types for entity definitions that have a view.
 *
 * ========================
 */
/**
 * The constructor output of {@link DefinedViewEntityConstructor}.
 *
 * @category Internal
 */
export type DefinedViewEntityInstance<Context, Shape extends ShapeDefinition<AnyObject, any> | undefined, Events extends Readonly<Event>> = ViewEntity<Context, Shape extends ShapeDefinition<AnyObject, any> ? Shape['runtimeType'] : undefined, Events>;
/**
 * Output of {@link DefineViewEntity}.
 *
 * @category Internal
 */
export type DefinedViewEntityConstructor<EntityKey, Context, Shape extends ShapeDefinition<AnyObject, any> | undefined, Events extends Readonly<Event>> = Constructor<DefinedViewEntityInstance<Context, Shape, Events>, ConstructorParameters<typeof ViewEntity<Context, Shape extends ShapeDefinition<AnyObject, any> ? Shape['runtimeType'] : undefined>>> & StaticEntity<EntityKey, Shape>;
/**
 * Type for {@link EntitySuite.defineEntity}.
 *
 * @category Internal
 */
export type DefineViewEntity<Context> = <const EntityKey extends string, const Shape extends ShapeDefinition<AnyObject, any> | undefined, const Events extends ReadonlyArray<Constructor<Event>> = never>(params: DefineEntityParams<EntityKey, Shape, Events>) => DefinedViewEntityConstructor<EntityKey, Context, Shape, InstanceType<ArrayElement<NoInfer<Events>>> | EntityDestroyEvent>;
/**
 * ========================
 *
 * # Logic Entity
 *
 * Types for entity definitions that don't have a view. The only difference between these types and
 * the view types are that this uses `BaseEntity` instead of `ViewEntity.
 *
 * ========================
 */
/**
 * The constructor output of {@link DefinedLogicEntityConstructor}.
 *
 * @category Internal
 */
export type DefinedLogicEntityInstance<Context, Shape extends ShapeDefinition<AnyObject, any> | undefined, Events extends Readonly<Event>> = BaseEntity<Context, Shape extends ShapeDefinition<AnyObject, any> ? Shape['runtimeType'] : undefined, Events>;
/**
 * Output of {@link DefineLogicEntity}.
 *
 * @category Internal
 */
export type DefinedLogicEntityConstructor<EntityKey, Context, Shape extends ShapeDefinition<AnyObject, any> | undefined, Events extends Readonly<Event>> = Constructor<DefinedLogicEntityInstance<Context, Shape, Events>, ConstructorParameters<typeof BaseEntity<Context, Shape extends ShapeDefinition<AnyObject, any> ? Shape['runtimeType'] : undefined>>> & StaticEntity<EntityKey, Shape>;
/**
 * Type for {@link EntitySuite.defineEntity}.
 *
 * @category Internal
 */
export type DefineLogicEntity<Context> = <const EntityKey extends string, const Shape extends ShapeDefinition<AnyObject, any> | undefined, const Events extends ReadonlyArray<Constructor<Event>> = never>(params: DefineEntityParams<EntityKey, Shape, Events>) => DefinedLogicEntityConstructor<EntityKey, Context, Shape, InstanceType<ArrayElement<NoInfer<Events>>> | EntityDestroyEvent>;
/**
 * ========================
 *
 * # Entity Suite
 *
 * ========================
 */
/**
 * Output of {@link defineEntitySuite}, used to defining and creating entities.
 *
 * @category Internal
 */
export type EntitySuite<Context> = {
    /**
     * The suite's entity store constructor. Instantiate this and to add your first entities.
     *
     * All defined entities will also have a reference to this store so they can add additional
     * entities by themselves.
     */
    EntityStore: new <const RegisteredEntities extends Values<EntityStore['entityKeyConstructorMap']>>(params: Readonly<EntityStoreConstructorParams<Context, RegisteredEntities>>) => EntityStore<Context, RegisteredEntities>;
    /**
     * Define a standard entity (with a view). This is intended to be extended from your entity
     * class.
     */
    defineEntity: DefineViewEntity<Context>;
    /** Define an entity that doesn't have an attached view. These are likely to be rare. */
    defineLogicEntity: DefineLogicEntity<Context>;
    /**
     * A set of entity keys used within this entity suite. This will only be populated by all
     * classes that are defined with `defineEntity` or `defineLogicEntity` (so this will miss any
     * not-yet-resolved dynamic imports). This will be populated even before the classes are ever
     * instantiated.
     */
    entityKeys: Set<string>;
};
/**
 * This is the starting point of the @game-vir/entity package. Call this to produce the function
 * needed to define new entities and the store needed to add entity instances.
 *
 * @category Main
 */
export declare function defineEntitySuite<Context = undefined>(): EntitySuite<Context>;
/**
 * Converts {@link ParamsMap} to {@link ReverseParamsMap}.
 *
 * @category Internal
 */
export declare function reverseParamsMap(paramsMap: ParamsMap | undefined): ReverseParamsMap | undefined;
