import { EventEmitter } from '../event-emitter.js';
import { BasicExpression, OrderBy } from '../query/ir.js';
import { IndexInterface } from '../indexes/base-index.js';
import { ChangeMessage, Subscription, SubscriptionEvents, SubscriptionLoadSubsetErrorEvent, SubscriptionStatus, SubscriptionUnsubscribedEvent } from '../types.js';
import { CollectionImpl } from './index.js';
type RequestSnapshotOptions = {
    where?: BasicExpression<boolean>;
    signal?: AbortSignal;
    optimizedOnly?: boolean;
    trackLoadSubsetPromise?: boolean;
    /** Optional orderBy to pass to loadSubset for backend optimization */
    orderBy?: OrderBy;
    /** Optional limit to pass to loadSubset for backend optimization */
    limit?: number;
    /** Callback that receives the raw loadSubset result for external tracking */
    onLoadSubsetResult?: (result: Promise<void> | true) => void;
    /** Called when the local snapshot must fall back from an index to a scan. */
    onUnoptimized?: () => void;
};
type RequestLimitedSnapshotOptions = {
    orderBy: OrderBy;
    limit: number;
    /** All column values for cursor (first value used for local index, all values for sync layer) */
    minValues?: Array<unknown>;
    /** Row offset for offset-based pagination (passed to sync layer) */
    offset?: number;
    /** Whether to track the loadSubset promise on this subscription (default: true) */
    trackLoadSubsetPromise?: boolean;
    /** Callback that receives the raw loadSubset result for external tracking */
    onLoadSubsetResult?: (result: Promise<void> | true) => void;
};
type CollectionSubscriptionOptions = {
    includeInitialState?: boolean;
    /** Pre-compiled expression for filtering changes */
    whereExpression?: BasicExpression<boolean>;
    /** Callback to call when the subscription is unsubscribed */
    onUnsubscribe?: (event: SubscriptionUnsubscribedEvent) => void;
    /** Callback for subset-load failures scoped to this subscription. */
    onLoadSubsetError?: (event: SubscriptionLoadSubsetErrorEvent) => void;
};
export declare class CollectionSubscription extends EventEmitter<SubscriptionEvents> implements Subscription {
    private collection;
    private callback;
    private options;
    private loadedInitialState;
    private skipFiltering;
    private snapshotSent;
    /**
     * Track all loadSubset calls made by this subscription so we can unload them on cleanup.
     * We store the exact LoadSubsetOptions we passed to loadSubset to ensure symmetric unload.
     */
    private subsetDemands;
    private readonly requestedSubsetWhere;
    private sentKeys;
    private publishedRows;
    private stalePublishedRows;
    private limitedSnapshotRowCount;
    private lastSentKey;
    private filteredCallback;
    private orderByIndex;
    private _status;
    private _lastError;
    private pendingLoadSubsetPromises;
    private truncateCleanup;
    private truncateReplaySession;
    get status(): SubscriptionStatus;
    get lastError(): unknown | undefined;
    constructor(collection: CollectionImpl<any, any, any, any, any>, callback: (changes: Array<ChangeMessage<any, any>>) => void, options: CollectionSubscriptionOptions);
    /**
     * Handle collection truncate event by resetting state and re-requesting subsets.
     * This is called when the sync layer receives a must-refetch and clears all data.
     *
     * To prevent a flash of missing content, we buffer all changes (deletes from truncate
     * and inserts from refetch) until all loadSubset calls succeed, then emit them together.
     * A failed replay keeps the last published snapshot, resumes ordinary deltas,
     * and retains subset ownership so a later truncate can retry the replay.
     */
    private handleTruncate;
    private settleTruncateReplay;
    /** Publish only after every overlapping replay attempt has settled. */
    private checkTruncateReplayComplete;
    /**
     * Discard an incomplete current replay and restore the last publication.
     * Rows in that publication remain stale until a later source delta or replay
     * reconciles them with the source collection.
     */
    private abandonTruncateReplay;
    /** Publish the complete buffered replacement as one subscriber batch. */
    private flushTruncateReplay;
    /** Reduce a replay's raw delete/insert stream to one exact semantic delta. */
    private createPublicationDiff;
    private get isBufferingForTruncate();
    setOrderByIndex(index: IndexInterface<any>): void;
    /**
     * Check if an orderBy index has been set for this subscription
     */
    hasOrderByIndex(): boolean;
    /**
     * Set subscription status and emit events if changed
     */
    private setStatus;
    /** Observe an asynchronous subset load and restore status on settlement. */
    private observeLoadSubsetResult;
    private loadSubset;
    /** Create a fresh, abortable adapter acquisition for a replay generation. */
    private createSubsetAcquisition;
    /** Replace the adapter lease held for one logical subset demand. */
    private replaceSubsetAcquisition;
    /** Abort and release one current adapter acquisition. */
    private releaseSubsetDemand;
    /** Start and retain the first acquisition for one logical subset demand. */
    private startSubsetDemand;
    private recordLoadSubsetError;
    hasLoadedInitialState(): boolean;
    hasSentAtLeastOneSnapshot(): boolean;
    emitEvents(changes: Array<ChangeMessage<any, any>>): boolean;
    /**
     * Sends the snapshot to the callback.
     * Returns a boolean indicating if it succeeded.
     * It can only fail if there is no index to fulfill the request
     * and the optimizedOnly option is set to true,
     * or, the entire state was already loaded.
     */
    requestSnapshot(opts?: RequestSnapshotOptions): boolean;
    /** Release one exact subset request while keeping the subscription alive. */
    releaseSnapshot(where: BasicExpression<boolean>): void;
    /**
     * Sends a snapshot that fulfills the `where` clause and all rows are bigger or equal to the cursor.
     * Requires a range index to be set with `setOrderByIndex` prior to calling this method.
     * It uses that range index to load the items in the order of the index.
     *
     * For multi-column orderBy:
     * - Uses first value from `minValues` for LOCAL index operations (wide bounds, ensures no missed rows)
     * - Uses all `minValues` to build a precise composite cursor for SYNC layer loadSubset
     *
     * Note 1: it may load more rows than the provided LIMIT because it loads all values equal to the first cursor value + limit values greater.
     *         This is needed to ensure that it does not accidentally skip duplicate values when the limit falls in the middle of some duplicated values.
     * Note 2: it does not send keys that have already been sent before.
     */
    requestLimitedSnapshot({ orderBy, limit, minValues, offset, trackLoadSubsetPromise: shouldTrackLoadSubsetPromise, onLoadSubsetResult, }: RequestLimitedSnapshotOptions): void;
    /**
     * Filters and flips changes for keys that have not been sent yet.
     * Deletes are filtered out for keys that have not been sent yet.
     * Updates are flipped into inserts for keys that have not been sent yet.
     * Duplicate inserts are filtered out to prevent D2 multiplicity > 1.
     */
    private filterAndFlipChanges;
    /**
     * After a failed replay, the source collection is empty but subscribers still
     * hold the last good publication. Reconcile the first later source delta for
     * each retained key against that publication instead of treating it as a
     * duplicate insert.
     */
    private reconcileStalePublishedChanges;
    private trackPublishedRows;
    private trackSentKeys;
    /**
     * Mark that the subscription should not filter any changes.
     * This is used when includeInitialState is explicitly set to false,
     * meaning the caller doesn't want initial state but does want ALL future changes.
     */
    markAllStateAsSeen(): void;
    unsubscribe(): void;
}
export {};
