import { o as ModulesMap, p as CreateSystemOptionsNamed, R as Requirement, N as NamespacedSystem, w as RequirementWithId, aH as SystemInspection } from './plugins-Co2_xohI.cjs';

/**
 * Testing Utilities - Helpers for testing Directive systems
 *
 * Features:
 * - Mock resolvers with manual resolve/reject
 * - Fake timers integration (works with Vitest/Jest fake timers)
 * - Assertion helpers
 * - Facts history tracking
 * - Pending requirements tracking
 */

/**
 * Flush all pending microtasks by awaiting multiple rounds of `Promise.resolve()`.
 *
 * Call this after advancing fake timers to ensure all Promise callbacks
 * (including nested microtasks) have run before making assertions.
 *
 * @returns A promise that resolves after all pending microtasks have been drained.
 *
 * @example
 * ```typescript
 * vi.useFakeTimers();
 * system.start();
 * system.facts.userId = 1; // Triggers constraint
 * await flushMicrotasks(); // Let reconciliation start
 * vi.advanceTimersByTime(100); // Advance resolver delay
 * await flushMicrotasks(); // Let resolver complete
 * ```
 *
 * @public
 */
declare function flushMicrotasks(): Promise<void>;
/**
 * Wait for the system to settle with fake timers enabled.
 *
 * Repeatedly advances fake timers in discrete steps while flushing microtasks,
 * until no resolvers remain inflight or the time budget is exhausted.
 *
 * @param system - The Directive system to wait on (must expose {@link SystemInspection} via `inspect()`).
 * @param advanceTime - Function that advances fake timers by a given number of milliseconds (e.g., `vi.advanceTimersByTime`).
 * @param options - Configuration for total time budget, step size, and iteration limit.
 * @returns A promise that resolves once the system is idle.
 *
 * @throws Error if the system does not settle within the configured time budget.
 *
 * @example
 * ```typescript
 * vi.useFakeTimers();
 * const system = createSystem({ modules: [myModule] });
 * system.start();
 * system.dispatch({ type: "triggerAsync" });
 *
 * await settleWithFakeTimers(system, vi.advanceTimersByTime, {
 *   totalTime: 1000,
 *   stepSize: 10,
 * });
 *
 * expect(system.facts.result).toBe("done");
 * ```
 *
 * @public
 */
declare function settleWithFakeTimers(system: {
    inspect(): SystemInspection;
}, advanceTime: (ms: number) => void, options?: {
    /** Total time to advance (default: 5000ms) */
    totalTime?: number;
    /** Time to advance each step (default: 10ms) */
    stepSize?: number;
    /** Maximum iterations before giving up (default: 1000) */
    maxIterations?: number;
}): Promise<void>;
/**
 * Standalone fake timer controller for tests that do not use Vitest/Jest fake timers.
 *
 * @remarks
 * For most tests, prefer Vitest's `vi.useFakeTimers()` paired with
 * {@link settleWithFakeTimers} for better integration. Use this interface
 * only when you need a lightweight, framework-independent timer mock.
 *
 * @public
 */
interface FakeTimers {
    /** Advance time by a number of milliseconds, firing any timers that fall within the window. */
    advance(ms: number): Promise<void>;
    /** Advance to the next scheduled timer and fire its callback. */
    next(): Promise<void>;
    /** Run all pending timers in chronological order. */
    runAll(): Promise<void>;
    /** Get the current fake time in milliseconds. */
    now(): number;
    /** Reset the clock to time 0 and discard all scheduled timers. */
    reset(): void;
}
/**
 * Create standalone fake timers for testing without a framework timer mock.
 *
 * @remarks
 * For most tests, prefer Vitest's `vi.useFakeTimers()` paired with
 * {@link settleWithFakeTimers}. This factory is useful when you need an
 * isolated timer that does not interfere with global timer state.
 *
 * @returns A {@link FakeTimers} controller with `advance`, `next`, `runAll`, `now`, and `reset` methods.
 *
 * @example
 * ```typescript
 * const timers = createFakeTimers();
 * // schedule work, then:
 * await timers.advance(500);
 * expect(timers.now()).toBe(500);
 * ```
 *
 * @public
 */
declare function createFakeTimers(): FakeTimers;
/**
 * Context passed to mock resolver resolve functions.
 *
 * @public
 */
interface MockResolverContext {
    /** Facts object (use type assertion for specific facts) */
    facts: any;
    /** Abort signal for cancellation */
    signal: AbortSignal;
}
/**
 * Configuration for a simple mock resolver created via {@link createMockResolver}.
 *
 * @typeParam R - The requirement type this resolver handles.
 *
 * @public
 */
interface MockResolverOptions<R extends Requirement = Requirement> {
    /** Predicate to check if this resolver handles a given requirement. */
    requirement?: (req: Requirement) => req is R;
    /** Mock implementation invoked when the resolver runs. */
    resolve?: (req: R, ctx: MockResolverContext) => void | Promise<void>;
    /** Artificial delay in milliseconds before the resolver completes. */
    delay?: number;
    /** Error (or message string) to throw, simulating a resolver failure. */
    error?: Error | string;
    /** Array that receives every requirement passed to this resolver. */
    calls?: R[];
}
/** Internal resolver definition type for mock resolvers */
interface MockResolverDef {
    requirement: (req: Requirement) => boolean;
    resolve: (req: Requirement, ctx: MockResolverContext) => Promise<void>;
}
/**
 * Create a simple mock resolver that matches requirements by type and optionally
 * records calls, injects delays, or throws errors.
 *
 * @param typeOrOptions - A requirement type string, or a full {@link MockResolverOptions} object.
 * @returns A resolver definition that can be spread into a module's `resolvers` map.
 *
 * @example
 * ```typescript
 * const calls: Requirement[] = [];
 * const mock = createMockResolver({ requirement: (r): r is MyReq => r.type === "LOAD", calls });
 * ```
 *
 * @public
 */
declare function createMockResolver<R extends Requirement = Requirement>(typeOrOptions: string | MockResolverOptions<R>): MockResolverDef;
/**
 * A mock resolver that captures requirements for manual resolution.
 *
 * @remarks
 * Use this when you need fine-grained control over when and how requirements
 * resolve. Requirements are queued in `pending` and stay unresolved until you
 * explicitly call `resolve()` or `reject()`.
 *
 * @typeParam R - The requirement type this resolver handles.
 *
 * @public
 */
interface MockResolver<R extends Requirement = Requirement> {
    /** All requirements received by this resolver */
    readonly calls: R[];
    /** Pending requirements waiting to be resolved/rejected */
    readonly pending: Array<{
        requirement: R;
        resolve: (result?: unknown) => void;
        reject: (error: Error) => void;
    }>;
    /** Resolve the next pending requirement */
    resolve(result?: unknown): void;
    /** Reject the next pending requirement */
    reject(error: Error): void;
    /** Resolve all pending requirements */
    resolveAll(result?: unknown): void;
    /** Reject all pending requirements */
    rejectAll(error: Error): void;
    /** Clear call history and pending queue */
    reset(): void;
}
/**
 * Create a mock resolver that captures requirements instead of resolving them,
 * giving you manual control over when and how each requirement completes.
 *
 * @param _requirementType - The requirement `type` string this mock handles (used for documentation; matching is done by the test harness).
 * @returns A {@link MockResolver} with a `handler` function suitable for passing to {@link createTestSystem} mocks.
 *
 * @example
 * ```typescript
 * const fetchMock = mockResolver<{ type: "FETCH_USER"; id: string }>("FETCH_USER");
 *
 * const system = createTestSystem({
 *   modules: [userModule],
 *   mocks: {
 *     resolvers: {
 *       FETCH_USER: { resolve: fetchMock.handler },
 *     },
 *   },
 * });
 *
 * system.facts.userId = "123";
 * await flushMicrotasks();
 *
 * // Requirement is pending
 * expect(fetchMock.calls).toHaveLength(1);
 * expect(fetchMock.calls[0].id).toBe("123");
 *
 * // Manually resolve it
 * fetchMock.resolve({ name: "John" });
 * await flushMicrotasks();
 *
 * expect(system.facts.user).toEqual({ name: "John" });
 * ```
 *
 * @public
 */
declare function mockResolver<R extends Requirement = Requirement>(_requirementType: string): MockResolver<R> & {
    /** Handler that can be passed to createTestSystem mocks */
    handler: (req: Requirement, ctx: MockResolverContext) => Promise<void>;
};
/**
 * Record of a single fact change captured by the test tracking plugin.
 *
 * @public
 */
interface FactChangeRecord {
    /** The fact key that changed (without namespace prefix for namespaced systems) */
    key: string;
    /** The full key including namespace prefix (e.g., "test::value") */
    fullKey: string;
    /** The namespace (e.g., "test") - undefined for single-module systems */
    namespace?: string;
    /** The previous value */
    previousValue: unknown;
    /** The new value */
    newValue: unknown;
    /** Timestamp of the change */
    timestamp: number;
}
/**
 * A Directive system augmented with testing utilities.
 *
 * @remarks
 * Extends {@link NamespacedSystem} with event/resolver/fact tracking, idle
 * waiting, and assertion helpers. Created via {@link createTestSystem}.
 *
 * @typeParam Modules - The modules map that defines the system's schema.
 *
 * @public
 */
interface TestSystem<Modules extends ModulesMap> extends NamespacedSystem<Modules> {
    /**
     * Wait for all pending operations to complete.
     * @param maxWait - Maximum time to wait in ms (default: 5000)
     * @throws Error if timeout is exceeded with resolvers still inflight
     */
    waitForIdle(maxWait?: number): Promise<void>;
    /** Get the history of dispatched events */
    eventHistory: Array<{
        type: string;
        [key: string]: unknown;
    }>;
    /** Get resolver call history */
    resolverCalls: Map<string, Requirement[]>;
    /**
     * Get all requirements that have been generated (both resolved and pending).
     * Unlike `inspect().unmet`, this includes requirements that have already been handled.
     */
    readonly allRequirements: RequirementWithId[];
    /**
     * Get all fact changes since system start or last reset.
     */
    getFactsHistory(): FactChangeRecord[];
    /**
     * Reset the facts history tracking.
     */
    resetFactsHistory(): void;
    /** Assert that a requirement was created */
    assertRequirement(type: string): void;
    /** Assert that a resolver was called */
    assertResolverCalled(type: string, times?: number): void;
    /**
     * Assert that a fact was set to a specific value.
     */
    assertFactSet(key: string, value?: unknown): void;
    /**
     * Assert the number of times a fact was changed.
     */
    assertFactChanges(key: string, times: number): void;
}
/**
 * Options for {@link createTestSystem}, extending the standard system options
 * with mock resolver injection and automatic tracking.
 *
 * @typeParam Modules - The modules map that defines the system's schema.
 *
 * @public
 */
interface CreateTestSystemOptions<Modules extends ModulesMap> extends Omit<CreateSystemOptionsNamed<Modules>, "plugins"> {
    /** Mock resolvers by type */
    mocks?: {
        resolvers?: Record<string, MockResolverOptions>;
    };
    /** Additional plugins (tracking plugin is added automatically) */
    plugins?: Array<any>;
}
/**
 * Create a Directive system instrumented for testing.
 *
 * Wraps {@link createSystem} with an automatic tracking plugin that records
 * dispatched events, resolver calls, fact changes, and generated requirements.
 * Mock resolvers can be injected via `options.mocks.resolvers` to replace
 * real resolvers by requirement type.
 *
 * @param options - System configuration with optional mock resolvers and additional plugins.
 * @returns A {@link TestSystem} with assertion helpers, idle waiting, and history tracking.
 *
 * @example
 * ```typescript
 * const system = createTestSystem({
 *   modules: { counter: counterModule },
 *   mocks: { resolvers: { INCREMENT: { resolve: (req, context) => { context.facts.count++; } } } },
 * });
 * system.start();
 * ```
 *
 * @public
 */
declare function createTestSystem<Modules extends ModulesMap>(options: CreateTestSystemOptions<Modules>): TestSystem<Modules>;
/**
 * Assert that a definition was dynamically registered on the system.
 *
 * @param system - The Directive system to check.
 * @param type - The definition type: "constraint", "resolver", "derivation", or "effect".
 * @param id - The definition ID.
 * @throws Error if the definition is not dynamic.
 *
 * @example
 * ```typescript
 * system.constraints.register("myRule", { when: () => true, require: { type: "DO" } });
 * assertDynamic(system, "constraint", "myRule"); // passes
 * assertDynamic(system, "constraint", "staticRule"); // throws
 * ```
 *
 * @public
 */
declare function assertDynamic(system: {
    constraints: {
        isDynamic(id: string): boolean;
    };
    effects: {
        isDynamic(id: string): boolean;
    };
    resolvers: {
        isDynamic(id: string): boolean;
    };
    derive: {
        isDynamic(id: string): boolean;
    };
}, type: "constraint" | "resolver" | "derivation" | "effect", id: string): void;
/**
 * Assert that a definition is NOT dynamically registered (i.e., is static or does not exist).
 *
 * @param system - The Directive system to check.
 * @param type - The definition type: "constraint", "resolver", "derivation", or "effect".
 * @param id - The definition ID.
 * @throws Error if the definition is dynamic.
 *
 * @example
 * ```typescript
 * assertNotDynamic(system, "constraint", "staticRule"); // passes
 * system.constraints.register("myRule", def);
 * assertNotDynamic(system, "constraint", "myRule"); // throws
 * ```
 *
 * @public
 */
declare function assertNotDynamic(system: {
    constraints: {
        isDynamic(id: string): boolean;
    };
    effects: {
        isDynamic(id: string): boolean;
    };
    resolvers: {
        isDynamic(id: string): boolean;
    };
    derive: {
        isDynamic(id: string): boolean;
    };
}, type: "constraint" | "resolver" | "derivation" | "effect", id: string): void;

export { type CreateTestSystemOptions, type FactChangeRecord, type FakeTimers, type MockResolver, type MockResolverContext, type MockResolverOptions, type TestSystem, assertDynamic, assertNotDynamic, createFakeTimers, createMockResolver, createTestSystem, flushMicrotasks, mockResolver, settleWithFakeTimers };
