import ECSpresso, { type InstallPluginParam } from "./ecspresso";
import type { ResourceFactoryWithDeps, ResourceDirectValue } from "./resource-manager";
import { type Plugin } from "./plugin";
import type { WorldConfig, EmptyConfig, MergeConfigs, TypesAreCompatible, WithComponents, WithEvents, WithResources } from "./type-utils";
import type { AssetConfiguratorFn, AssetsResource } from "./asset-types";
import type { ScreenDefinition, ScreenConfigurator, ScreenResource } from "./screen-types";
/**
 * Helper type: finalize built-in resources ($assets, $screen) in the resource map.
 * Auto-injects $assets/$screen when plugins contribute asset/screen types even without
 * explicit withAssets()/withScreens(). Also narrows the AssetGroupNames on $assets.
 */
type FinalizeBuiltinResources<Cfg extends WorldConfig, AG extends string> = {
    readonly components: Cfg['components'];
    readonly events: Cfg['events'];
    readonly resources: Omit<Cfg['resources'], '$assets' | '$screen'> & ([keyof Cfg['assets']] extends [never] ? {} : {
        $assets: AssetsResource<Cfg['assets'], AG>;
    }) & ([keyof Cfg['screens']] extends [never] ? {} : {
        $screen: ScreenResource<Cfg['screens']>;
    });
    readonly assets: Cfg['assets'];
    readonly screens: Cfg['screens'];
};
/**
    * Builder class for ECSpresso that provides fluent type-safe plugin installation.
    * Handles type checking during build process to ensure type safety.
*/
export declare class ECSpressoBuilder<Cfg extends WorldConfig = EmptyConfig, Labels extends string = never, Groups extends string = never, AssetGroupNames extends string = never, ReactiveQueryNames extends string = never> {
    /** Asset configurator for collecting asset definitions */
    private assetConfigurator;
    /** Screen configurator for collecting screen definitions */
    private screenConfigurator;
    /** Pending resources to add during build */
    private pendingResources;
    /** Pending dispose callbacks to register during build */
    private pendingDisposeCallbacks;
    /** Pending required component registrations to apply during build */
    private pendingRequiredComponents;
    /** Pending plugins to install during build */
    private pendingPlugins;
    /** Fixed timestep interval (null means use default 1/60) */
    private _fixedDt;
    /** True when `.disableChangeTracking()` was called; flips the runtime into "track nothing" at build. */
    private _disableChangeTracking;
    constructor();
    /**
        * Add the first plugin when starting with empty types.
        * This overload allows any plugin to be added to an empty ECSpresso instance.
        * Only merges the plugin's Provides (PCfg) into accumulated config, not its Requires (PReq).
    */
    withPlugin<PCfg extends WorldConfig, PReq extends WorldConfig = EmptyConfig, BL extends string = never, BG extends string = never, BAG extends string = never, BRQ extends string = never>(this: ECSpressoBuilder<{
        readonly components: {};
        readonly events: {};
        readonly resources: {};
        readonly assets: Cfg['assets'];
        readonly screens: Cfg['screens'];
    }, Labels, Groups, AssetGroupNames, ReactiveQueryNames>, plugin: Plugin<PCfg, PReq, BL, BG, BAG, BRQ>): ECSpressoBuilder<MergeConfigs<Cfg, PCfg>, Labels | BL, Groups | BG, AssetGroupNames | BAG, ReactiveQueryNames | BRQ>;
    /**
        * Add a subsequent plugin with type checking.
        * This overload enforces plugin type compatibility and requirement satisfaction.
        * Only merges the plugin's Provides (PCfg) into accumulated config, not its Requires (PReq).
    */
    withPlugin<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>): ECSpressoBuilder<MergeConfigs<Cfg, PCfg>, Labels | BL, Groups | BG, AssetGroupNames | BAG, ReactiveQueryNames | BRQ>;
    /**
     * Add application-specific component types to the builder chain.
     * This is a pure type-level operation with no runtime cost.
     * Conflicts with existing component types (same key, different type) produce a `never` return.
     */
    withComponentTypes<T extends Record<string, any>>(): TypesAreCompatible<Cfg['components'], T> extends true ? ECSpressoBuilder<WithComponents<Cfg, T>, Labels, Groups, AssetGroupNames, ReactiveQueryNames> : never;
    /**
     * Add application-specific event types to the builder chain.
     * This is a pure type-level operation with no runtime cost.
     * Conflicts with existing event types (same key, different type) produce a `never` return.
     */
    withEventTypes<T extends Record<string, any>>(): TypesAreCompatible<Cfg['events'], T> extends true ? ECSpressoBuilder<WithEvents<Cfg, T>, Labels, Groups, AssetGroupNames, ReactiveQueryNames> : never;
    /**
     * Add application-specific resource types to the builder chain.
     * This is a pure type-level operation with no runtime cost.
     * Conflicts with existing resource types (same key, different type) produce a `never` return.
     */
    withResourceTypes<T extends Record<string, any>>(): TypesAreCompatible<Cfg['resources'], T> extends true ? ECSpressoBuilder<WithResources<Cfg, T>, Labels, Groups, AssetGroupNames, ReactiveQueryNames> : never;
    /**
     * Opt out of change tracking entirely. After this call every `markChanged`
     * (and `commands.markChanged`) is a runtime no-op, and `changed:` filters
     * yield nothing. Useful for worlds with no reactive consumers (e.g. the
     * physics bench) to skip the per-mark sequence stamp and array allocation.
     *
     * By default, change tracking is auto-derived: any system that declares a
     * `changed:` filter auto-subscribes those components, and all other marks
     * become no-ops. If no system declares `changed:`, every mark is recorded
     * (track-all default). Call this to force the no-op-everything mode.
     */
    disableChangeTracking(): this;
    /**
     * Add a resource during ECSpresso construction.
     *
     * When the key matches a pre-declared resource type (via `withResourceTypes`, `create<C,E,R>()`,
     * or plugin resources), the value is validated against that type.
     * For new keys, the value type is inferred as before.
     *
     * @param key The resource key
     * @param resource The resource value, factory function, or factory with dependencies/disposal
     * @returns This builder with updated resource types
     */
    withResource<K extends keyof Cfg['resources'] & string>(key: K, resource: Cfg['resources'][K] | ((context: ECSpresso<Cfg>) => Cfg['resources'][K] | Promise<Cfg['resources'][K]>) | ResourceFactoryWithDeps<Cfg['resources'][K], ECSpresso<Cfg>, keyof Cfg['resources'] & string> | ResourceDirectValue<Cfg['resources'][K]>): ECSpressoBuilder<Cfg, Labels, Groups, AssetGroupNames, ReactiveQueryNames>;
    withResource<K extends string, V>(key: K & ([K] extends [keyof Cfg['resources']] ? [V] extends [Cfg['resources'][K & keyof Cfg['resources']]] ? string : never : string), resource: V | ((context: ECSpresso<WithResources<Cfg, Record<K, V>>>) => V | Promise<V>) | ResourceFactoryWithDeps<V, ECSpresso<WithResources<Cfg, Record<K, V>>>, keyof (Cfg['resources'] & Record<K, V>) & string> | ResourceDirectValue<V>): ECSpressoBuilder<WithResources<Cfg, Record<K, V>>, Labels, Groups, AssetGroupNames, ReactiveQueryNames>;
    /**
     * Register a dispose callback for a component type during build.
     * Called when a component is removed (explicit removal, entity destruction, or replacement).
     * @param componentName The component type to register disposal for
     * @param callback Function receiving the component value being disposed
     * @returns This builder for method chaining
     */
    withDispose<K extends keyof Cfg['components'] & string>(componentName: K, callback: (ctx: {
        value: Cfg['components'][K];
        entityId: number;
    }) => void): this;
    /**
     * Register a required component relationship during build.
     * When an entity gains `trigger`, the `required` component is auto-added
     * (using `factory` for the default value) if not already present.
     * @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
     * @returns This builder for method chaining
     */
    withRequired<Trigger extends keyof Cfg['components'] & string, Required extends keyof Cfg['components'] & string>(trigger: Trigger, required: Required, factory: (triggerValue: Cfg['components'][Trigger]) => Cfg['components'][Required]): this;
    /**
     * Configure assets for this ECSpresso instance
     * @param configurator Function that receives an AssetConfigurator and returns it after adding assets
     * @returns This builder with updated asset types
     */
    withAssets<NewAssets extends Record<string, unknown>, NewAssetGroups extends string = never>(configurator: AssetConfiguratorFn<NewAssets, NewAssetGroups>): ECSpressoBuilder<{
        readonly components: Cfg['components'];
        readonly events: Cfg['events'];
        readonly resources: Cfg['resources'] & {
            $assets: AssetsResource<Cfg['assets'] & NewAssets, string>;
        };
        readonly assets: Cfg['assets'] & NewAssets;
        readonly screens: Cfg['screens'];
    }, Labels, Groups, AssetGroupNames | NewAssetGroups, ReactiveQueryNames>;
    /**
     * Configure screens for this ECSpresso instance
     * @param configurator Function that receives a ScreenConfigurator and returns it after adding screens
     * @returns This builder with updated screen types
     */
    withScreens<NewS extends Record<string, ScreenDefinition<any, any>>>(configurator: (screens: ScreenConfigurator<{}, ECSpresso<{
        readonly components: Cfg['components'];
        readonly events: Cfg['events'];
        readonly resources: Cfg['resources'];
        readonly assets: Cfg['assets'];
        readonly screens: Record<string, ScreenDefinition>;
    }>>) => ScreenConfigurator<NewS, ECSpresso<{
        readonly components: Cfg['components'];
        readonly events: Cfg['events'];
        readonly resources: Cfg['resources'];
        readonly assets: Cfg['assets'];
        readonly screens: Record<string, ScreenDefinition>;
    }>>): ECSpressoBuilder<{
        readonly components: Cfg['components'];
        readonly events: Cfg['events'];
        readonly resources: Cfg['resources'] & {
            $screen: ScreenResource<Cfg['screens'] & NewS>;
        };
        readonly assets: Cfg['assets'];
        readonly screens: Cfg['screens'] & NewS;
    }, Labels, Groups, AssetGroupNames, ReactiveQueryNames>;
    /**
     * Configure the fixed timestep interval for the fixedUpdate phase.
     * @param dt The fixed timestep in seconds (e.g., 1/60 for 60Hz physics)
     * @returns This builder for method chaining
     */
    withFixedTimestep(dt: number): this;
    /**
     * Declare reactive query names that will be registered at runtime.
     * This is a pure type-level operation with no runtime cost.
     */
    withReactiveQueryNames<N extends string>(): ECSpressoBuilder<Cfg, Labels, Groups, AssetGroupNames, ReactiveQueryNames | N>;
    /**
     * Create a plugin factory from the builder's accumulated 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>;
    /**
        * Complete the build process and return the built ECSpresso instance
    */
    build(): ECSpresso<FinalizeBuiltinResources<Cfg, [AssetGroupNames] extends [never] ? string : AssetGroupNames>, [
        Labels
    ] extends [never] ? string : Labels, [
        Groups
    ] extends [never] ? string : Groups, [
        AssetGroupNames
    ] extends [never] ? string : AssetGroupNames, [
        ReactiveQueryNames
    ] extends [never] ? string : ReactiveQueryNames>;
}
export {};
