import type { LogContext } from '@rocicorp/logger';
import type { PlanDebugger } from './planner-debug.ts';
import type { PlannerConnection } from './planner-connection.ts';
import type { PlannerConstraint } from './planner-constraint.ts';
import type { PlannerFanIn } from './planner-fan-in.ts';
import type { PlannerFanOut } from './planner-fan-out.ts';
import type { PlannerJoin } from './planner-join.ts';
import { PlannerSource, type ConnectionCostModel } from './planner-source.ts';
import type { PlannerTerminus } from './planner-terminus.ts';
/**
 * Captured state of a plan for comparison and restoration.
 */
export type PlanState = {
    connections: Array<{
        limit: number | undefined;
    }>;
    joins: Array<{
        type: 'semi' | 'flipped';
    }>;
    fanOuts: Array<{
        type: 'FO' | 'UFO';
    }>;
    fanIns: Array<{
        type: 'FI' | 'UFI';
    }>;
    connectionConstraints: Array<Map<string, PlannerConstraint | undefined>>;
};
export declare class PlannerGraph {
    #private;
    joins: PlannerJoin[];
    fanOuts: PlannerFanOut[];
    fanIns: PlannerFanIn[];
    connections: PlannerConnection[];
    /**
     * Reset all planning state back to initial values for another planning pass.
     * Resets only mutable planning state - graph structure is unchanged.
     *
     * This allows replanning the same query graph with different strategies.
     */
    resetPlanningState(): void;
    /**
     * Create and register a source (table) in the graph.
     */
    addSource(name: string, model: ConnectionCostModel): PlannerSource;
    /**
     * Get a source by table name.
     */
    getSource(name: string): PlannerSource;
    /**
     * Check if a source exists by table name.
     */
    hasSource(name: string): boolean;
    /**
     * Set the terminus (final output) node of the graph.
     * Constraint propagation starts from this node.
     */
    setTerminus(terminus: PlannerTerminus): void;
    /**
     * Initiate constraint propagation from the terminus node.
     * This sends constraints up through the graph to update
     * connection cost estimates.
     */
    propagateConstraints(planDebugger?: PlanDebugger): void;
    /**
     * Calculate total cost of the current plan.
     * Total cost includes both startup cost (one-time, e.g., sorting) and running cost.
     */
    getTotalCost(planDebugger?: PlanDebugger): number;
    /**
     * Capture a lightweight snapshot of the current planning state.
     * Used for backtracking during multi-start greedy search.
     *
     * Captures mutable state including pinned flags, join types, and
     * constraint maps to avoid needing repropagation on restore.
     *
     * @returns A snapshot that can be restored via restorePlanningSnapshot()
     */
    capturePlanningSnapshot(): PlanState;
    /**
     * Restore planning state from a previously captured snapshot.
     * Used for backtracking when a planning attempt fails.
     *
     * Restores pinned flags, join types, and constraint maps, eliminating
     * the need for repropagation.
     *
     * @param state - Snapshot created by capturePlanningSnapshot()
     */
    restorePlanningSnapshot(state: PlanState): void;
    /**
     * Main planning algorithm using exhaustive join flip enumeration.
     *
     * Enumerates all possible flip patterns for flippable joins (2^n for n flippable joins).
     * Each pattern represents a different query execution plan. We evaluate the cost of each
     * plan and select the one with the lowest cost.
     *
     * Connections are used only for cost estimation - the flip patterns determine the plan.
     * FanOut/FanIn states (FO/UFO and FI/UFI) are automatically derived from join flip states.
     *
     * @param planDebugger - Optional debugger to receive structured events during planning
     * @param lc - Optional logger for warnings
     */
    plan(planDebugger?: PlanDebugger, lc?: LogContext): void;
}
//# sourceMappingURL=planner-graph.d.ts.map