/**
 * Resource factory with declared dependencies and optional disposal callback
 */
export interface ResourceFactoryWithDeps<T, Context = unknown, D extends string = string> {
    dependsOn?: readonly D[];
    factory: (context: Context) => T | Promise<T>;
    onDispose?: (resource: T, context: Context) => void | Promise<void>;
}
/** @internal */
export declare const RESOURCE_DIRECT: unique symbol;
/**
 * Branded wrapper for storing a value as-is, bypassing factory detection.
 * The value is carried on the symbol key to avoid structural conflicts
 * with user resource types that have a `value` property.
 * Create via the `directValue()` helper.
 */
export interface ResourceDirectValue<T> {
    [RESOURCE_DIRECT]: T;
}
/**
 * Wrap a value to store it as-is, bypassing factory detection.
 * Use when the resource itself is a function or class that should not be invoked.
 *
 * @example
 * ```ts
 * import { directValue } from 'ecspresso';
 * world.addResource('handler', directValue(myFunction));
 * world.addResource('MyClass', directValue(MyClass));
 * ```
 */
export declare function directValue<T>(value: T): ResourceDirectValue<T>;
/**
 * When Context is unknown (default), context args are optional.
 * When Context is a specific type (e.g. ECSpresso<...>), context is required.
 */
type ContextArgs<Context> = unknown extends Context ? [context?: Context] : [context: Context];
export default class ResourceManager<ResourceTypes extends Record<string, any> = Record<string, any>, Context = unknown> {
    private resources;
    private resourceFactories;
    private resourceDependencies;
    private resourceDisposers;
    private initializedResourceKeys;
    private _changeSubscribers;
    /** Shallow snapshots of observed resources, keyed by resource key */
    private _observedSnapshots;
    /**
     * Add a resource to the manager.
     *
     * Resolution order:
     * 1. `{ factory, dependsOn?, onDispose? }` → factory with optional deps/disposal
     * 2. `{ value }` → direct value wrapper (use to store functions/classes as-is)
     * 3. `typeof === 'function'` → bare factory (no deps)
     * 4. Anything else → direct value
     *
     * @param label The resource key
     * @param resource The resource value, a factory function, or a factory with dependencies
     * @returns The resource manager instance for chaining
     */
    add<K extends keyof ResourceTypes>(label: K, resource: ResourceTypes[K] | ((context: Context) => ResourceTypes[K] | Promise<ResourceTypes[K]>) | ResourceFactoryWithDeps<ResourceTypes[K], Context, keyof ResourceTypes & string> | ResourceDirectValue<ResourceTypes[K]>): this;
    /**
     * Try to get a resource from the manager.
     * Returns the resource value if it exists, or undefined if not found.
     * Like `get`, initializes factory resources on first access.
     * @param label The resource key
     * @param context Context to pass to factory functions (usually the ECSpresso instance)
     * @returns The resource value, or undefined if not found
     * @see get — the throwing alternative
     */
    tryGet<K extends keyof ResourceTypes>(label: K, ...args: ContextArgs<Context>): ResourceTypes[K] | undefined;
    /**
     * Get a resource from the manager
     * @param label The resource key
     * @param context Context to pass to factory functions (usually the ECSpresso instance)
     * @returns The resource value
     * @throws Error if resource not found
     * @see tryGet — the non-throwing alternative
     */
    get<K extends keyof ResourceTypes>(label: K, ...args: ContextArgs<Context>): ResourceTypes[K];
    /**
     * Check if a resource exists
     * @param label The resource key
     * @returns True if the resource exists
     */
    has<K extends keyof ResourceTypes>(label: K): boolean;
    /**
     * Remove a resource (without calling onDispose)
     * @param label The resource key
     * @returns True if the resource was removed
     */
    remove<K extends keyof ResourceTypes>(label: K): boolean;
    /**
     * Get all resource keys
     * @returns Array of resource keys
     */
    getKeys(): Array<keyof ResourceTypes>;
    /**
     * Check if a resource needs to be initialized
     * @param label The resource key
     * @returns True if the resource needs initialization
     */
    needsInitialization<K extends keyof ResourceTypes>(label: K): boolean;
    /**
     * Get all resource keys that need to be initialized
     * @returns Array of resource keys that need initialization
     */
    getPendingInitializationKeys(): Array<keyof ResourceTypes>;
    /**
     * Initialize a specific resource if it's a factory function
     * @param label The resource key
     * @param context Context to pass to factory functions
     * @returns Promise that resolves when the resource is initialized
     */
    initializeResource<K extends keyof ResourceTypes>(label: K, ...args: ContextArgs<Context>): Promise<void>;
    /**
     * Initialize specific resources or all resources that haven't been initialized yet.
     * Resources are initialized in topological order based on their dependencies.
     * @param context Context to pass to factory functions (usually the ECSpresso instance)
     * @param keys Optional array of resource keys to initialize
     * @returns Promise that resolves when the specified resources are initialized
     */
    initializeResources<K extends keyof ResourceTypes>(...args: [...ContextArgs<Context>, ...K[]]): Promise<void>;
    /**
     * Get the dependencies of a resource
     * @param label The resource key
     * @returns Array of resource keys that this resource depends on
     */
    getDependencies<K extends keyof ResourceTypes>(label: K): readonly (keyof ResourceTypes & string)[];
    /**
     * Dispose a single resource, calling its onDispose callback if it exists
     * @param label The resource key to dispose
     * @param context Context to pass to the onDispose callback
     * @returns True if the resource existed and was disposed, false if it didn't exist
     */
    disposeResource<K extends keyof ResourceTypes>(label: K, ...args: ContextArgs<Context>): Promise<boolean>;
    /**
     * Subscribe to changes for a specific resource key.
     *
     * Subscribing marks the resource as "observed." Observed resources:
     * - Are re-resolved each frame by `withResources` (no stale cache)
     * - Are shallow-diffed at the end of each frame via `flushObserved()`,
     *   so in-place mutations are detected and subscribers notified
     *
     * When the last subscriber unsubscribes, the resource reverts to
     * normal (cached, no per-frame diff).
     *
     * @param key The resource key to watch
     * @param callback Function called with (newValue, oldValue) when the resource changes
     * @returns Unsubscribe function
     */
    onResourceChange<K extends keyof ResourceTypes>(key: K, callback: (newValue: ResourceTypes[K], oldValue: ResourceTypes[K]) => void): () => void;
    /**
     * Notify subscribers of a resource value change.
     * Skips notification if the value is unchanged (via Object.is).
     * @param key The resource key that changed
     * @param newValue The new resource value
     * @param oldValue The previous resource value
     */
    notifyChange<K extends keyof ResourceTypes>(key: K, newValue: ResourceTypes[K], oldValue: ResourceTypes[K]): void;
    /**
     * Whether a resource has active change subscribers.
     * Observed resources should not be cached by systems — they need
     * to be re-resolved each frame so external mutations are visible.
     */
    isObserved<K extends keyof ResourceTypes>(key: K): boolean;
    /**
     * Diff all observed resources against their snapshots.
     * Fires subscribers for any resource whose shallow properties changed
     * since the last snapshot, then updates the snapshot.
     * Call once per frame after all systems have run.
     */
    flushObserved(): void;
    /**
     * Dispose all initialized resources in reverse dependency order.
     * Resources that depend on others are disposed first.
     * @param context Context to pass to onDispose callbacks
     */
    disposeResources(...args: ContextArgs<Context>): Promise<void>;
}
export {};
