import * as mongodb from 'mongodb';
import { ObjectId, FindCursor, WithId, Db, Collection } from 'mongodb';
export { ObjectId } from 'mongodb';
import * as bson from 'bson';

interface Fact<TFactType extends string, TData = never, TMetadata = never> {
    streamId: ObjectId;
    revision: number;
    type: TFactType;
    time: Date;
    data: TData;
    metadata: TMetadata;
}
type UnknownFact = Fact<string, unknown, unknown>;
type FactReducer<S, F extends UnknownFact> = (state: S | null, fact: F) => S | null | Promise<S | null>;
interface FactStore<F extends UnknownFact> {
    append: (fact: F) => Promise<F>;
    onAfterAppend: (callback: (fact: F) => Promise<void>) => void;
    onBeforeAppend: (callback: (fact: F) => Promise<F>) => void;
    find: (streamId: ObjectId | string) => FindCursor<WithId<F>>;
    findAll: () => FindCursor<WithId<F>>;
    mongoDatabase: Db;
}
interface CreateFactStoreOptions {
    name: string;
}
interface FactStreamsDatabase {
    createFactStore: <T extends UnknownFact>(options: CreateFactStoreOptions) => Promise<FactStore<T>>;
    mongoDatabase: Db;
    close: () => Promise<void>;
}
interface ConnectOptions {
    uri: string;
    dbName: string;
}

declare function connect(options: ConnectOptions): Promise<FactStreamsDatabase>;

declare function createFact<F extends UnknownFact>(streamId: ObjectId, type: F['type'], data: F['data'], metadata: F['metadata']): F;

declare const NEW: ObjectId;

type StateResult<S> = S | null | Promise<S | null>;
declare class View<S, F extends UnknownFact> {
    #private;
    constructor(factStore: FactStore<F>);
    on<SF extends F>(type: SF['type'], reducer: FactReducer<S, SF>): View<S, F>;
    onUnknownFact(callback: (state: S | null, fact: F) => StateResult<S>): View<S, F>;
    onDone(callback: (state: S | null) => StateResult<S>): View<S, F>;
    createPersistent(collectionName: string): Promise<{
        aggregate: <T extends bson.Document = bson.Document>(pipeline?: bson.Document[] | undefined, options?: mongodb.AggregateOptions | undefined) => mongodb.AggregationCursor<T>;
        countDocuments: (filter?: mongodb.Filter<WithId<S>> | undefined, options?: mongodb.CountDocumentsOptions | undefined) => Promise<number>;
        distinct: {
            <Key extends "_id" | keyof mongodb.EnhancedOmit<WithId<S>, "_id">>(key: Key): Promise<mongodb.Flatten<WithId<WithId<S>>[Key]>[]>;
            <Key_1 extends "_id" | keyof mongodb.EnhancedOmit<WithId<S>, "_id">>(key: Key_1, filter: mongodb.Filter<WithId<S>>): Promise<mongodb.Flatten<WithId<WithId<S>>[Key_1]>[]>;
            <Key_2 extends "_id" | keyof mongodb.EnhancedOmit<WithId<S>, "_id">>(key: Key_2, filter: mongodb.Filter<WithId<S>>, options: mongodb.CommandOperationOptions): Promise<mongodb.Flatten<WithId<WithId<S>>[Key_2]>[]>;
            (key: string): Promise<any[]>;
            (key: string, filter: mongodb.Filter<WithId<S>>): Promise<any[]>;
            (key: string, filter: mongodb.Filter<WithId<S>>, options: mongodb.CommandOperationOptions): Promise<any[]>;
        };
        find: {
            (): mongodb.FindCursor<WithId<WithId<S>>>;
            (filter: mongodb.Filter<WithId<S>>, options?: mongodb.FindOptions<bson.Document> | undefined): mongodb.FindCursor<WithId<WithId<S>>>;
            <T_1 extends bson.Document>(filter: mongodb.Filter<WithId<S>>, options?: mongodb.FindOptions<bson.Document> | undefined): mongodb.FindCursor<T_1>;
        };
        findOne: {
            (): Promise<WithId<WithId<S>> | null>;
            (filter: mongodb.Filter<WithId<S>>): Promise<WithId<WithId<S>> | null>;
            (filter: mongodb.Filter<WithId<S>>, options: mongodb.FindOptions<bson.Document>): Promise<WithId<WithId<S>> | null>;
            <T_2 = WithId<S>>(): Promise<T_2 | null>;
            <T_3 = WithId<S>>(filter: mongodb.Filter<WithId<S>>): Promise<T_3 | null>;
            <T_4 = WithId<S>>(filter: mongodb.Filter<WithId<S>>, options?: mongodb.FindOptions<bson.Document> | undefined): Promise<T_4 | null>;
        };
        collection: Collection<WithId<S>>;
        replayFacts: (streamId: ObjectId) => Promise<S | null>;
        rebuild: (streamId: ObjectId) => Promise<void>;
    }>;
    createTransient(): Promise<(streamId: ObjectId) => Promise<S | null>>;
}

export { ConnectOptions, CreateFactStoreOptions, Fact, FactReducer, FactStore, FactStreamsDatabase, NEW, UnknownFact, View, connect, createFact };
