import type { AggregationCursor, ChangeStream, ChangeStreamDocument, ChangeStreamInsertDocument, Document, MongoAPIError, MongoServerError } from 'mongodb';
import { type Options as RetryOptions } from 'p-retry';
import type { LastFlush, QueueStats } from 'prom-utils';
export type Cursor = ChangeStream | AggregationCursor;
export type JSONSchema = Record<string, any>;
type MaybePromise<T> = T | Promise<T>;
/**
 * Extract the operationType field from a type.
 * Create a union of all possible operation types.
 */
type ExtractOperationType<T> = T extends {
    operationType: infer Type;
} ? Type : never;
/**
 * Mapping from operation type to document type. For example, if the operation
 * type is 'insert', the document type is ChangeStreamInsertDocument.
 */
type OperationTypeMap = {
    [K in ExtractOperationType<ChangeStreamDocument>]: Extract<ChangeStreamDocument, {
        operationType: K;
    }>;
};
/**
 * Union of all possible operation types - 'insert' | 'update' | 'delete' etc.
 */
export type OperationType = keyof OperationTypeMap;
/**
 * Extract the specific document types from an array of operation types.
 * For example, if the type parameter is ['insert', 'update'], the return type
 * is ChangeStreamInsertDocument | ChangeStreamUpdateDocument.
 */
export type DocumentsForOperationTypes<T extends OperationType[] | undefined> = T extends OperationType[] ? OperationTypeMap[T[number]] : ChangeStreamDocument;
export type ProcessChangeStreamRecords<T extends OperationType[] | undefined = undefined> = (docs: DocumentsForOperationTypes<T>[]) => MaybePromise<void>;
export type ProcessInitialScanRecords = (docs: ChangeStreamInsertDocument[]) => MaybePromise<void>;
export interface SyncOptions {
    /** Field paths to omit. */
    omit?: string[];
    /**
     * Added to all Redis keys to allow the same collection
     * to be synced in parallel. Otherwise, the Redis keys
     * would be the same for a given collection and parallel
     * syncing jobs would overwrite each other.
     */
    uniqueId?: string;
    /**
     * Maximum time to pause in ms after calling `pausable.pause()`.
     * By default, pausing is indefinite.
     */
    maxPauseTime?: number;
    /**
     * Options for handling retry logic when calling `processRecords`.
     * Defaults to `{ minTimeout: 30s, maxTimeout: 1h, retries: 30 }`.
     * Options passed here will be applied over the default options.
     */
    retry?: RetryOptions;
}
export interface SortField<T> {
    field: string;
    /** Function to serialize value to string. */
    serialize: (x: T) => string;
    deserialize: (x: string) => T;
    /** Sort order: asc or desc. Defaults to asc */
    order?: 'asc' | 'desc';
}
export interface ScanOptions<T = any> {
    /** Defaults to _id */
    sortField?: SortField<T>;
    /** Extend the pipeline. Be careful not to exclude the sort field or change the sort order. */
    pipeline?: Document[];
}
export interface ChangeStreamOptions<T extends OperationType[] | undefined = undefined> {
    pipeline?: Document[];
    operationTypes?: T;
}
export interface ChangeOptions {
    /** How often to retrieve the schema and look for a change. */
    interval?: number;
    /**
     * Remove fields that are not used when converting the schema
     * in a downstream library like mongo2elastic or mongo2crate.
     * Preserves bsonType, properties, additionalProperties, items, and enum.
     */
    shouldRemoveUnusedFields?: boolean;
}
export type Events = 'cursorError' | 'resync' | 'schemaChange' | 'stateChange' | 'initialScanComplete' | 'stats' | 'processError';
export interface ResyncEvent {
    type: 'resync';
}
export interface SchemaChangeEvent {
    type: 'schemaChange';
    previousSchema?: JSONSchema;
    currentSchema: JSONSchema;
}
export interface StateChangeEvent {
    type: 'stateChange';
    name: string;
    from: string;
    to: string;
}
export interface InitialScanCompleteEvent {
    type: 'initialScanComplete';
}
export type CursorError = MongoServerError | MongoAPIError;
export interface CursorErrorEvent {
    type: 'cursorError';
    name: 'runInitialScan' | 'processChangeStream';
    error: CursorError;
}
export interface ProcessErrorEvent {
    type: 'processError';
    name: 'runInitialScan' | 'processChangeStream';
    error: unknown;
}
/**
 * If `maxItemsPerSec` is not set, `stats.itemsPerSec` will be 0.
 * If `maxBytesPerSec` is not set, `stats.bytesPerSec` will be 0.
 */
export interface StatsEvent {
    type: 'stats';
    name: 'runInitialScan' | 'processChangeStream';
    stats: QueueStats;
    lastFlush?: LastFlush;
}
export type State = 'starting' | 'started' | 'stopping' | 'stopped';
export type SimpleState = 'started' | 'stopped';
export {};
