import * as i0 from '@angular/core';
import { InjectionToken, NgZone, ModuleWithProviders } from '@angular/core';
import { ɵAngularFireSchedulers as _AngularFireSchedulers } from '@angular/fire';
import { AppCheckInstances } from '@angular/fire/app-check';
import { AngularFireAuth } from '@angular/fire/compat/auth';
import { FirebaseOptions } from 'firebase/app';
import firebase from 'firebase/compat/app';
import { Subscriber, Observable, SchedulerLike } from 'rxjs';

type Settings = firebase.firestore.Settings;
type CollectionReference<T = DocumentData> = firebase.firestore.CollectionReference<T>;
type DocumentReference<T = DocumentData> = firebase.firestore.DocumentReference<T>;
type PersistenceSettings = firebase.firestore.PersistenceSettings;
type DocumentChangeType = firebase.firestore.DocumentChangeType;
type SnapshotOptions = firebase.firestore.SnapshotOptions;
type FieldPath = firebase.firestore.FieldPath;
type Query<T = DocumentData> = firebase.firestore.Query<T>;
type SetOptions = firebase.firestore.SetOptions;
type DocumentData = firebase.firestore.DocumentData;
interface DocumentSnapshotExists<T> extends firebase.firestore.DocumentSnapshot<T> {
    readonly exists: true;
    data(options?: SnapshotOptions): T;
}
interface DocumentSnapshotDoesNotExist extends firebase.firestore.DocumentSnapshot {
    readonly exists: false;
    data(options?: SnapshotOptions): undefined;
    get(fieldPath: string | FieldPath, options?: SnapshotOptions): undefined;
}
type DocumentSnapshot<T> = DocumentSnapshotExists<T> | DocumentSnapshotDoesNotExist;
interface QueryDocumentSnapshot<T> extends firebase.firestore.QueryDocumentSnapshot<T> {
    data(options?: SnapshotOptions): T;
}
interface QuerySnapshot<T> extends firebase.firestore.QuerySnapshot<T> {
    readonly docs: QueryDocumentSnapshot<T>[];
}
interface DocumentChange<T> extends firebase.firestore.DocumentChange<T> {
    readonly doc: QueryDocumentSnapshot<T>;
}
interface DocumentChangeAction<T> {
    type: DocumentChangeType;
    payload: DocumentChange<T>;
}
interface Action<T> {
    type: string;
    payload: T;
}
interface Reference {
    onSnapshot: (options: firebase.firestore.SnapshotListenOptions, sub: Subscriber<any>) => any;
}
type QueryFn<T = DocumentData> = (ref: CollectionReference<T>) => Query<T>;
type QueryGroupFn<T = DocumentData> = (query: Query<T>) => Query<T>;
/**
 * A structure that provides an association between a reference
 * and a query on that reference. Note: Performing operations
 * on the reference can lead to confusing results with complicated
 * queries.
 *
 * Example:
 *
 * const query = ref.where('type', '==', 'Book').
 *                  .where('price', '>' 18.00)
 *                  .where('price', '<' 100.00)
 *                  .where('category', '==', 'Fiction')
 *                  .where('publisher', '==', 'BigPublisher')
 *
 * // This addition would not be a result of the query above
 * ref.add({
 *  type: 'Magazine',
 *  price: 4.99,
 *  category: 'Sports',
 *  publisher: 'SportsPublisher'
 * });
 */
interface AssociatedReference<T = DocumentData> {
    ref: CollectionReference<T>;
    query: Query<T>;
}

/**
 * AngularFirestoreDocument service
 *
 * This class creates a reference to a Firestore Document. A reference is provided in
 * in the constructor. The class is generic which gives you type safety for data update
 * methods and data streaming.
 *
 * This class uses Symbol.observable to transform into Observable using Observable.from().
 *
 * This class is rarely used directly and should be created from the AngularFirestore service.
 *
 * Example:
 *
 * const fakeStock = new AngularFirestoreDocument<Stock>(doc('stocks/FAKE'));
 * await fakeStock.set({ name: 'FAKE', price: 0.01 });
 * fakeStock.valueChanges().map(snap => {
 *   if(snap.exists) return snap.data();
 *   return null;
 * }).subscribe(value => console.log(value));
 * // OR! Transform using Observable.from() and the data is unwrapped for you
 * Observable.from(fakeStock).subscribe(value => console.log(value));
 */
declare class AngularFirestoreDocument<T = DocumentData> {
    ref: DocumentReference<T>;
    private afs;
    private readonly injector;
    /**
     * The constructor takes in a DocumentReference to provide wrapper methods
     * for data operations, data streaming, and Symbol.observable.
     */
    constructor(ref: DocumentReference<T>, afs: AngularFirestore);
    /**
     * Create or overwrite a single document.
     */
    set(data: T, options?: SetOptions): Promise<void>;
    /**
     * Update some fields of a document without overwriting the entire document.
     */
    update(data: Partial<T>): Promise<void>;
    /**
     * Delete a document.
     */
    delete(): Promise<void>;
    /**
     * Create a reference to a sub-collection given a path and an optional query
     * function.
     */
    collection<R = DocumentData>(path: string, queryFn?: QueryFn): AngularFirestoreCollection<R>;
    /**
     * Listen to snapshot updates from the document.
     */
    snapshotChanges(): Observable<Action<DocumentSnapshot<T>>>;
    /**
     * Listen to unwrapped snapshot updates from the document.
     *
     * If the `idField` option is provided, document IDs are included and mapped to the
     * provided `idField` property name.
     */
    valueChanges(options?: unknown): Observable<T | undefined>;
    valueChanges<K extends string>(options: {
        idField: K;
    }): Observable<(T & {
        [T in K]: string;
    }) | undefined>;
    /**
     * Retrieve the document once.
     */
    get(options?: firebase.firestore.GetOptions): Observable<firebase.firestore.DocumentSnapshot<T>>;
}

declare function validateEventsArray(events?: DocumentChangeType[]): firebase.firestore.DocumentChangeType[];
/**
 * AngularFirestoreCollection service
 *
 * This class creates a reference to a Firestore Collection. A reference and a query are provided in
 * in the constructor. The query can be the unqueried reference if no query is desired.The class
 * is generic which gives you type safety for data update methods and data streaming.
 *
 * This class uses Symbol.observable to transform into Observable using Observable.from().
 *
 * This class is rarely used directly and should be created from the AngularFirestore service.
 *
 * Example:
 *
 * const collectionRef = firebase.firestore.collection('stocks');
 * const query = collectionRef.where('price', '>', '0.01');
 * const fakeStock = new AngularFirestoreCollection<Stock>(collectionRef, query);
 *
 * // NOTE!: the updates are performed on the reference not the query
 * await fakeStock.add({ name: 'FAKE', price: 0.01 });
 *
 * // Subscribe to changes as snapshots. This provides you data updates as well as delta updates.
 * fakeStock.valueChanges().subscribe(value => console.log(value));
 */
declare class AngularFirestoreCollection<T = DocumentData> {
    readonly ref: CollectionReference<T>;
    private readonly query;
    private readonly afs;
    private readonly injector;
    /**
     * The constructor takes in a CollectionReference and Query to provide wrapper methods
     * for data operations and data streaming.
     *
     * Note: Data operation methods are done on the reference not the query. This means
     * when you update data it is not updating data to the window of your query unless
     * the data fits the criteria of the query. See the AssociatedRefence type for details
     * on this implication.
     */
    constructor(ref: CollectionReference<T>, query: Query<T>, afs: AngularFirestore);
    /**
     * Listen to the latest change in the stream. This method returns changes
     * as they occur and they are not sorted by query order. This allows you to construct
     * your own data structure.
     */
    stateChanges(events?: DocumentChangeType[]): Observable<DocumentChangeAction<T>[]>;
    /**
     * Create a stream of changes as they occur it time. This method is similar to stateChanges()
     * but it collects each event in an array over time.
     */
    auditTrail(events?: DocumentChangeType[]): Observable<DocumentChangeAction<T>[]>;
    /**
     * Create a stream of synchronized changes. This method keeps the local array in sorted
     * query order.
     */
    snapshotChanges(events?: DocumentChangeType[]): Observable<DocumentChangeAction<T>[]>;
    /**
     * Listen to all documents in the collection and its possible query as an Observable.
     *
     * If the `idField` option is provided, document IDs are included and mapped to the
     * provided `idField` property name.
     */
    valueChanges(): Observable<T[]>;
    valueChanges({}: {}): Observable<T[]>;
    valueChanges<K extends string>(options: {
        idField: K;
    }): Observable<(T & {
        [T in K]: string;
    })[]>;
    /**
     * Retrieve the results of the query once.
     */
    get(options?: firebase.firestore.GetOptions): Observable<firebase.firestore.QuerySnapshot<T>>;
    /**
     * Add data to a collection reference.
     *
     * Note: Data operation methods are done on the reference not the query. This means
     * when you update data it is not updating data to the window of your query unless
     * the data fits the criteria of the query.
     */
    add(data: T): Promise<DocumentReference<T>>;
    /**
     * Create a reference to a single document in a collection.
     */
    doc<T2 = T>(path?: string): AngularFirestoreDocument<T2>;
}

/**
 * AngularFirestoreCollectionGroup service
 *
 * This class holds a reference to a Firestore Collection Group Query.
 *
 * This class uses Symbol.observable to transform into Observable using Observable.from().
 *
 * This class is rarely used directly and should be created from the AngularFirestore service.
 *
 * Example:
 *
 * const collectionGroup = firebase.firestore.collectionGroup('stocks');
 * const query = collectionRef.where('price', '>', '0.01');
 * const fakeStock = new AngularFirestoreCollectionGroup<Stock>(query, afs);
 *
 * // Subscribe to changes as snapshots. This provides you data updates as well as delta updates.
 * fakeStock.valueChanges().subscribe(value => console.log(value));
 */
declare class AngularFirestoreCollectionGroup<T = DocumentData> {
    private readonly query;
    private readonly afs;
    private readonly injector;
    /**
     * The constructor takes in a CollectionGroupQuery to provide wrapper methods
     * for data operations and data streaming.
     */
    constructor(query: Query<T>, afs: AngularFirestore);
    /**
     * Listen to the latest change in the stream. This method returns changes
     * as they occur and they are not sorted by query order. This allows you to construct
     * your own data structure.
     */
    stateChanges(events?: DocumentChangeType[]): Observable<DocumentChangeAction<T>[]>;
    /**
     * Create a stream of changes as they occur it time. This method is similar to stateChanges()
     * but it collects each event in an array over time.
     */
    auditTrail(events?: DocumentChangeType[]): Observable<DocumentChangeAction<T>[]>;
    /**
     * Create a stream of synchronized changes. This method keeps the local array in sorted
     * query order.
     */
    snapshotChanges(events?: DocumentChangeType[]): Observable<DocumentChangeAction<T>[]>;
    /**
     * Listen to all documents in the collection and its possible query as an Observable.
     *
     * If the `idField` option is provided, document IDs are included and mapped to the
     * provided `idField` property name.
     */
    valueChanges(): Observable<T[]>;
    valueChanges({}: {}): Observable<T[]>;
    valueChanges<K extends string>(options: {
        idField: K;
    }): Observable<(T & {
        [T in K]: string;
    })[]>;
    /**
     * Retrieve the results of the query once.
     */
    get(options?: firebase.firestore.GetOptions): Observable<firebase.firestore.QuerySnapshot<T>>;
}

/**
 * The value of this token determines whether or not the firestore will have persistance enabled
 */
declare const ENABLE_PERSISTENCE: InjectionToken<boolean>;
declare const PERSISTENCE_SETTINGS: InjectionToken<firebase.firestore.PersistenceSettings>;
declare const SETTINGS: InjectionToken<firebase.firestore.Settings>;
declare const USE_EMULATOR: InjectionToken<[host: string, port: number, options?: {
    mockUserToken?: firebase.firestore.EmulatorMockTokenOptions | string;
}]>;
/**
 * A utility methods for associating a collection reference with
 * a query.
 *
 * @param collectionRef - A collection reference to query
 * @param queryFn - The callback to create a query
 *
 * Example:
 * const { query, ref } = associateQuery(docRef.collection('items'), ref => {
 *  return ref.where('age', '<', 200);
 * });
 */
declare function associateQuery<T>(collectionRef: CollectionReference<T>, queryFn?: (ref: any) => any): AssociatedReference<T>;
/**
 * AngularFirestore Service
 *
 * This service is the main entry point for this feature module. It provides
 * an API for creating Collection and Reference services. These services can
 * then be used to do data updates and observable streams of the data.
 *
 * Example:
 *
 * import { Component } from '@angular/core';
 * import { AngularFirestore, AngularFirestoreCollection, AngularFirestoreDocument } from '@angular/fire/firestore';
 * import { Observable } from 'rxjs/Observable';
 * import { from } from 'rxjs/observable';
 *
 * @Component({
 *   selector: 'app-my-component',
 *   template: `
 *    <h2>Items for {{ (profile | async)?.name }}
 *    <ul>
 *       <li *ngFor="let item of items | async">{{ item.name }}</li>
 *    </ul>
 *    <div class="control-input">
 *       <input type="text" #itemname />
 *       <button (click)="addItem(itemname.value)">Add Item</button>
 *    </div>
 *   `
 * })
 * export class MyComponent implements OnInit {
 *
 *   // services for data operations and data streaming
 *   private readonly itemsRef: AngularFirestoreCollection<Item>;
 *   private readonly profileRef: AngularFirestoreDocument<Profile>;
 *
 *   // observables for template
 *   items: Observable<Item[]>;
 *   profile: Observable<Profile>;
 *
 *   // inject main service
 *   constructor(private readonly afs: AngularFirestore) {}
 *
 *   ngOnInit() {
 *     this.itemsRef = afs.collection('items', ref => ref.where('user', '==', 'davideast').limit(10));
 *     this.items = this.itemsRef.valueChanges().map(snap => snap.docs.map(data => doc.data()));
 *     // this.items = from(this.itemsRef); // you can also do this with no mapping
 *
 *     this.profileRef = afs.doc('users/davideast');
 *     this.profile = this.profileRef.valueChanges();
 *   }
 *
 *   addItem(name: string) {
 *     const user = 'davideast';
 *     this.itemsRef.add({ name, user });
 *   }
 * }
 */
declare class AngularFirestore {
    schedulers: _AngularFireSchedulers;
    readonly firestore: firebase.firestore.Firestore;
    readonly persistenceEnabled$: Observable<boolean>;
    private readonly ngZone;
    /**
     * Each Feature of AngularFire has a FirebaseApp injected. This way we
     * don't rely on the main Firebase App instance and we can create named
     * apps and use multiple apps.
     */
    constructor(options: FirebaseOptions, name: string | null | undefined, shouldEnablePersistence: boolean | null, settings: Settings | null, platformId: Object, zone: NgZone, schedulers: _AngularFireSchedulers, persistenceSettings: PersistenceSettings | null, _useEmulator: any, auth: AngularFireAuth, useAuthEmulator: any, authSettings: any, // can't use firebase.auth.AuthSettings here
    tenantId: string | null, languageCode: string | null, useDeviceLanguage: boolean | null, persistence: string | null, _appCheckInstances: AppCheckInstances);
    /**
     * Create a reference to a Firestore Collection based on a path or
     * CollectionReference and an optional query function to narrow the result
     * set.
     */
    collection<T>(path: string, queryFn?: QueryFn): AngularFirestoreCollection<T>;
    collection<T>(ref: CollectionReference, queryFn?: QueryFn): AngularFirestoreCollection<T>;
    /**
     * Create a reference to a Firestore Collection Group based on a collectionId
     * and an optional query function to narrow the result
     * set.
     */
    collectionGroup<T>(collectionId: string, queryGroupFn?: QueryGroupFn<T>): AngularFirestoreCollectionGroup<T>;
    /**
     * Create a reference to a Firestore Document based on a path or
     * DocumentReference. Note that documents are not queryable because they are
     * simply objects. However, documents have sub-collections that return a
     * Collection reference and can be queried.
     */
    doc<T>(path: string): AngularFirestoreDocument<T>;
    doc<T>(ref: DocumentReference): AngularFirestoreDocument<T>;
    /**
     * Returns a generated Firestore Document Id.
     */
    createId(): string;
    static ɵfac: i0.ɵɵFactoryDeclaration<AngularFirestore, [null, { optional: true; }, { optional: true; }, { optional: true; }, null, null, null, { optional: true; }, { optional: true; }, { optional: true; }, { optional: true; }, { optional: true; }, { optional: true; }, { optional: true; }, { optional: true; }, { optional: true; }, { optional: true; }]>;
    static ɵprov: i0.ɵɵInjectableDeclaration<AngularFirestore>;
}

declare class AngularFirestoreModule {
    constructor();
    /**
     * Attempt to enable persistent storage, if possible
     */
    static enablePersistence(persistenceSettings?: PersistenceSettings): ModuleWithProviders<AngularFirestoreModule>;
    static ɵfac: i0.ɵɵFactoryDeclaration<AngularFirestoreModule, never>;
    static ɵmod: i0.ɵɵNgModuleDeclaration<AngularFirestoreModule, never, never, never>;
    static ɵinj: i0.ɵɵInjectorDeclaration<AngularFirestoreModule>;
}

/**
 * Return a stream of document changes on a query. These results are not in sort order but in
 * order of occurence.
 */
declare function docChanges<T>(query: Query, scheduler?: SchedulerLike): Observable<DocumentChangeAction<T>[]>;
/**
 * Return a stream of document changes on a query. These results are in sort order.
 */
declare function sortedChanges<T>(query: Query, events: DocumentChangeType[], scheduler?: SchedulerLike): Observable<DocumentChangeAction<T>[]>;
/**
 * Combines the total result set from the current set of changes from an incoming set
 * of changes.
 */
declare function combineChanges<T>(current: DocumentChange<T>[], changes: DocumentChange<T>[], events: DocumentChangeType[]): DocumentChange<T>[];
/**
 * Creates a new sorted array from a new change.
 * Build our own because we allow filtering of action types ('added', 'removed', 'modified') before scanning
 * and so we have greater control over change detection (by breaking ===)
 */
declare function combineChange<T>(combined: DocumentChange<T>[], change: DocumentChange<T>): DocumentChange<T>[];

declare function fromRef<R, T>(ref: DocumentReference<T> | Query<T>, scheduler?: SchedulerLike): Observable<R>;
declare function fromDocRef<T>(ref: DocumentReference<T>, scheduler?: SchedulerLike): Observable<Action<DocumentSnapshot<T>>>;
declare function fromCollectionRef<T>(ref: Query<T>, scheduler?: SchedulerLike): Observable<Action<QuerySnapshot<T>>>;

export { AngularFirestore, AngularFirestoreCollection, AngularFirestoreCollectionGroup, AngularFirestoreDocument, AngularFirestoreModule, ENABLE_PERSISTENCE, PERSISTENCE_SETTINGS, SETTINGS, USE_EMULATOR, associateQuery, combineChange, combineChanges, docChanges, fromCollectionRef, fromDocRef, fromRef, sortedChanges, validateEventsArray };
export type { Action, AssociatedReference, CollectionReference, DocumentChange, DocumentChangeAction, DocumentChangeType, DocumentData, DocumentReference, DocumentSnapshot, DocumentSnapshotDoesNotExist, DocumentSnapshotExists, FieldPath, PersistenceSettings, Query, QueryDocumentSnapshot, QueryFn, QueryGroupFn, QuerySnapshot, Reference, SetOptions, Settings, SnapshotOptions };
