/**
 * State Machine Plugin for ECSpresso
 *
 * Provides ECS-native finite state machines with guard-based transitions,
 * event-driven transitions, and lifecycle hooks (onEnter, onExit, onUpdate).
 *
 * Each entity gets a `stateMachine` component referencing a shared definition.
 * One system processes all state machine entities each tick.
 */
import { type BasePluginOptions } from 'ecspresso';
import type { BaseWorld } from 'ecspresso';
/** BaseWorld narrowed to state-machine components for typed access in helpers. */
type StateMachineWorld = BaseWorld<StateMachineComponentTypes>;
/**
 * Configuration for a single state in a state machine definition.
 *
 * @template S - Union of state name strings
 * @template W - World interface type for hooks/guards (default: StateMachineWorld)
 */
export interface StateConfig<S extends string, W extends BaseWorld<StateMachineComponentTypes> = StateMachineWorld> {
    /** Called when entering this state */
    onEnter?(ctx: {
        ecs: W;
        entityId: number;
    }): void;
    /** Called when exiting this state */
    onExit?(ctx: {
        ecs: W;
        entityId: number;
    }): void;
    /** Called each tick while in this state */
    onUpdate?(ctx: {
        ecs: W;
        entityId: number;
        dt: number;
    }): void;
    /** Guard-based transitions evaluated each tick. First passing guard wins. */
    transitions?: ReadonlyArray<{
        target: S;
        guard(ctx: {
            ecs: W;
            entityId: number;
        }): boolean;
    }>;
    /** Event-based transition map: eventName → target state or guarded transition */
    on?: Record<string, S | {
        target: S;
        guard(ctx: {
            ecs: W;
            entityId: number;
        }): boolean;
    }>;
}
/**
 * Immutable definition of a state machine. Shared across entities.
 *
 * @template S - Union of state name strings
 */
export interface StateMachineDefinition<S extends string> {
    readonly id: string;
    readonly initial: S;
    readonly states: {
        readonly [K in S]: StateConfig<S>;
    };
}
/**
 * Runtime state machine component stored on each entity.
 *
 * @template S - Union of state name strings (default: string)
 */
export interface StateMachine<S extends string = string> {
    readonly definition: StateMachineDefinition<string>;
    current: S;
    previous: S | null;
    stateTime: number;
}
/**
 * Component types provided by the state machine plugin.
 *
 * @template S - Union of state name strings (default: string)
 */
export interface StateMachineComponentTypes<S extends string = string> {
    stateMachine: StateMachine<S>;
}
/**
 * Event published on every state transition.
 *
 * @template S - Union of state name strings (default: string)
 */
export interface StateTransitionEvent<S extends string = string> {
    entityId: number;
    from: S;
    to: S;
    definitionId: string;
}
/**
 * Event types provided by the state machine plugin.
 *
 * @template S - Union of state name strings (default: string)
 */
export interface StateMachineEventTypes<S extends string = string> {
    stateTransition: StateTransitionEvent<S>;
}
/**
 * Extract the state name union from a StateMachineDefinition.
 *
 * @example
 * ```typescript
 * const enemyFSM = defineStateMachine('enemy', { initial: 'idle', states: { idle: {}, chase: {} } });
 * type EnemyStates = StatesOf<typeof enemyFSM>; // 'idle' | 'chase'
 * type AllStates = StatesOf<typeof enemyFSM> | StatesOf<typeof playerFSM>;
 * ```
 */
export type StatesOf<D> = D extends StateMachineDefinition<infer S> ? S : never;
/**
 * Configuration options for the state machine plugin.
 */
export interface StateMachinePluginOptions<G extends string = 'stateMachine'> extends BasePluginOptions<G> {
}
/**
 * Define a state machine with type-safe state names.
 *
 * @template S - Union of state name strings, inferred from `states` keys
 * @param id - Unique identifier for this definition
 * @param config - Initial state and state configurations
 * @returns A frozen StateMachineDefinition
 *
 * @example
 * ```typescript
 * const enemyFSM = defineStateMachine('enemy', {
 *   initial: 'idle',
 *   states: {
 *     idle: {
 *       onEnter: ({ ecs, entityId }) => { ... },
 *       transitions: [{ target: 'chase', guard: ({ ecs, entityId }) => playerNearby(ecs, entityId) }],
 *     },
 *     chase: {
 *       onUpdate: ({ ecs, entityId, dt }) => { ... },
 *       on: { playerLost: 'idle' },
 *     },
 *   },
 * });
 * ```
 */
export declare function defineStateMachine<S extends string>(id: string, config: {
    initial: NoInfer<S>;
    states: Record<S, StateConfig<NoInfer<S>>>;
}): StateMachineDefinition<S>;
/**
 * Create a stateMachine component from a definition.
 *
 * @param definition - The state machine definition to use
 * @param options - Optional overrides (e.g., initial state)
 * @returns Component object suitable for spreading into spawn()
 *
 * @example
 * ```typescript
 * ecs.spawn({
 *   ...createStateMachine(enemyFSM),
 *   position: { x: 100, y: 200 },
 * });
 * ```
 */
export declare function createStateMachine<S extends string>(definition: StateMachineDefinition<S>, options?: {
    initial?: S;
}): Pick<StateMachineComponentTypes<S>, 'stateMachine'>;
/**
 * Directly transition an entity's state machine to a target state.
 * Fires onExit, onEnter hooks and publishes stateTransition event.
 *
 * @param ecs - ECS instance (structural typing)
 * @param entityId - Entity to transition
 * @param targetState - State to transition to
 * @returns true if transition succeeded, false if entity has no stateMachine or target state doesn't exist
 */
export declare function transitionTo(ecs: StateMachineWorld, entityId: number, targetState: string): boolean;
/**
 * Send a named event to an entity's state machine.
 * Checks the current state's `on` handlers for a matching event.
 *
 * @param ecs - ECS instance (structural typing)
 * @param entityId - Entity to send event to
 * @param eventName - Event name to match against `on` handlers
 * @returns true if a transition occurred, false otherwise
 */
export declare function sendEvent(ecs: StateMachineWorld, entityId: number, eventName: string): boolean;
/**
 * Get the current state of an entity's state machine.
 *
 * @param ecs - ECS instance (structural typing)
 * @param entityId - Entity to query
 * @returns The current state string, or undefined if entity has no stateMachine
 */
export declare function getStateMachineState(ecs: StateMachineWorld, entityId: number): string | undefined;
/**
 * Typed helpers for the state machine plugin.
 * Creates helpers that validate hook parameters against the world type W.
 * Call after .build() using typeof ecs.
 */
export interface StateMachineHelpers<W extends BaseWorld<StateMachineComponentTypes>> {
    defineStateMachine: <S extends string>(id: string, config: {
        initial: NoInfer<S>;
        states: Record<S, StateConfig<NoInfer<S>, W>>;
    }) => StateMachineDefinition<S>;
}
export declare function createStateMachineHelpers<W extends BaseWorld<StateMachineComponentTypes> = StateMachineWorld>(_world?: W): StateMachineHelpers<W>;
/**
 * Create a state machine plugin for ECSpresso.
 *
 * Provides:
 * - Lifecycle hooks (onEnter, onExit, onUpdate) per state
 * - Guard-based automatic transitions evaluated each tick
 * - Event-based transitions via `sendEvent()`
 * - Direct transitions via `transitionTo()`
 * - stateTransition events published on every transition
 *
 * @example
 * ```typescript
 * const ecs = ECSpresso.create()
 *   .withPlugin(createStateMachinePlugin())
 *   .build();
 *
 * const fsm = defineStateMachine('enemy', {
 *   initial: 'idle',
 *   states: {
 *     idle: {
 *       transitions: [{ target: 'chase', guard: ({ ecs, entityId }) => playerNearby(ecs, entityId) }],
 *     },
 *     chase: {
 *       onUpdate: ({ ecs, entityId, dt }) => moveTowardPlayer(ecs, entityId, dt),
 *       on: { playerLost: 'idle' },
 *     },
 *   },
 * });
 *
 * ecs.spawn({
 *   ...createStateMachine(fsm),
 *   position: { x: 0, y: 0 },
 * });
 * ```
 */
export declare function createStateMachinePlugin<S extends string = string, G extends string = 'stateMachine'>(options?: StateMachinePluginOptions<G>): import("ecspresso").Plugin<import("ecspresso").WithEvents<import("ecspresso").WithComponents<import("ecspresso").EmptyConfig, StateMachineComponentTypes<S>>, StateMachineEventTypes<S>>, import("ecspresso").EmptyConfig, "state-machine-update", G, never, never>;
export {};
