import type { BaseItem, PersistenceAdapter, ReactivityAdapter, Changeset, LoadResponse } from '@signaldb/core';
import { Collection } from '@signaldb/core';
import PromiseQueue from './utils/PromiseQueue';
import type { Change, Snapshot, SyncOperation } from './types';
type SyncOptions<T extends Record<string, any>> = {
    name: string;
} & T;
type CleanupFunction = (() => void | Promise<void>) | void;
interface Options<CollectionOptions extends Record<string, any>, ItemType extends BaseItem<IdType> = BaseItem, IdType = any> {
    pull: (collectionOptions: SyncOptions<CollectionOptions>, pullParameters: {
        lastFinishedSyncStart?: number;
        lastFinishedSyncEnd?: number;
    }) => Promise<LoadResponse<ItemType>>;
    push: (collectionOptions: SyncOptions<CollectionOptions>, pushParameters: {
        rawChanges: Omit<Change, 'id' | 'collectionName'>[];
        changes: Changeset<ItemType> & {
            modifiedFields: Map<IdType, string[]>;
        };
    }) => Promise<void>;
    registerRemoteChange?: (collectionOptions: SyncOptions<CollectionOptions>, onChange: (data?: LoadResponse<ItemType>) => Promise<void>) => CleanupFunction | Promise<CleanupFunction>;
    id?: string;
    persistenceAdapter?: (id: string, registerErrorHandler: (handler: (error: Error) => void) => void) => PersistenceAdapter<any, any>;
    reactivity?: ReactivityAdapter;
    onError?: (collectionOptions: SyncOptions<CollectionOptions>, error: Error) => void;
    autostart?: boolean;
    debounceTime?: number;
}
/**
 * Class to manage syncing of collections.
 * @template CollectionOptions
 * @template ItemType
 * @template IdType
 * @example
 * const syncManager = new SyncManager({
 *    pull: async (collectionOptions) => {
 *      const response = await fetch(`/api/collections/${collectionOptions.name}`)
 *      return await response.json()
 *    },
 *    push: async (collectionOptions, { changes }) => {
 *      await fetch(`/api/collections/${collectionOptions.name}`, {
 *        method: 'POST',
 *        body: JSON.stringify(changes),
 *      })
 *    },
 *  })
 *
 *  const collection = new Collection()
 *  syncManager.addCollection(collection, {
 *    name: 'todos',
 *  })
 *
 *  syncManager.sync('todos')
 */
export default class SyncManager<CollectionOptions extends Record<string, any>, ItemType extends BaseItem<IdType> = BaseItem, IdType = any> {
    protected options: Options<CollectionOptions, ItemType, IdType>;
    protected collections: Map<string, {
        collection: Collection<ItemType, IdType, any>;
        options: SyncOptions<CollectionOptions>;
        readyPromise: Promise<void>;
        syncPaused: boolean;
        cleanupFunction?: CleanupFunction;
    }>;
    protected changes: Collection<Change<ItemType>, string>;
    protected snapshots: Collection<Snapshot<ItemType>, string>;
    protected syncOperations: Collection<SyncOperation, string>;
    protected scheduledPushes: Set<string>;
    protected remoteChanges: Omit<Change, 'id' | 'time'>[];
    protected syncQueues: Map<string, PromiseQueue>;
    protected persistenceReady: Promise<void>;
    protected isDisposed: boolean;
    protected instanceId: string;
    protected id: string;
    protected debouncedFlush: () => void;
    /**
     * @param options Collection options
     * @param options.pull Function to pull data from remote source.
     * @param options.push Function to push data to remote source.
     * @param [options.registerRemoteChange] Function to register a callback for remote changes.
     * @param [options.id] Unique identifier for this sync manager. Only nessesary if you have multiple sync managers.
     * @param [options.persistenceAdapter] Persistence adapter to use for storing changes, snapshots and sync operations.
     * @param [options.reactivity] Reactivity adapter to use for reactivity.
     * @param [options.onError] Function to handle errors that occur async during syncing.
     * @param [options.autostart] Whether to automatically start syncing new collections.
     * @param [options.debounceTime] The time in milliseconds to debounce push operations.
     */
    constructor(options: Options<CollectionOptions, ItemType, IdType>);
    protected createPersistenceAdapter(name: string): {
        adapter: PersistenceAdapter<any, any>;
        handler: (error: Error) => void;
    } | undefined;
    protected getSyncQueue(name: string): PromiseQueue;
    /**
     * Clears all internal data structures
     */
    dispose(): Promise<void>;
    /**
     * Gets a collection with it's options by name
     * @deprecated Use getCollectionProperties instead.
     * @param name Name of the collection
     * @throws Will throw an error if the name wasn't found
     * @returns Tuple of collection and options
     */
    getCollection(name: string): (Collection<ItemType, IdType, any> | SyncOptions<CollectionOptions>)[];
    /**
     * Gets collection options by name
     * @param name Name of the collection
     * @throws Will throw an error if the name wasn't found
     * @returns An object of all properties of the collection
     */
    getCollectionProperties(name: string): {
        collection: Collection<ItemType, IdType, any>;
        options: SyncOptions<CollectionOptions>;
        readyPromise: Promise<void>;
        syncPaused: boolean;
        cleanupFunction?: CleanupFunction | undefined;
    };
    /**
     * Adds a collection to the sync manager.
     * @param collection Collection to add
     * @param options Options for the collection. The object needs at least a `name` property.
     * @param options.name Unique name of the collection
     */
    addCollection(collection: Collection<ItemType, IdType, any>, options: SyncOptions<CollectionOptions>): void;
    protected flushScheduledPushes(): void;
    protected schedulePush(name: string): void;
    /**
     * Setup all collections to be synced with remote changes
     * and enable automatic pushing changes to the remote source.
     */
    startAll(): Promise<void>;
    /**
     * Setup a collection to be synced with remote changes
     * and enable automatic pushing changes to the remote source.
     * @param name Name of the collection
     */
    startSync(name: string): Promise<void>;
    /**
     * Pauses the sync process for all collections.
     * This means that the collections will not be synced with remote changes
     * and changes will not automatically be pushed to the remote source.
     */
    pauseAll(): Promise<void>;
    /**
     * Pauses the sync process for a collection.
     * This means that the collection will not be synced with remote changes
     * and changes will not automatically be pushed to the remote source.
     * @param name Name of the collection
     */
    pauseSync(name: string): Promise<void>;
    /**
     * Starts the sync process for all collections
     */
    syncAll(): Promise<void>;
    /**
     * Checks if a collection is currently beeing synced
     * @param [name] Name of the collection. If not provided, it will check if any collection is currently beeing synced.
     * @returns True if the collection is currently beeing synced, false otherwise.
     */
    isSyncing(name?: string): boolean;
    /**
     * Checks if the sync manager is ready to sync.
     * @returns A promise that resolves when the sync manager is ready to sync.
     */
    isReady(): Promise<void>;
    /**
     * Starts the sync process for a collection
     * @param name Name of the collection
     * @param options Options for the sync process.
     * @param options.force If true, the sync process will be started even if there are no changes and onlyWithChanges is true.
     * @param options.onlyWithChanges If true, the sync process will only be started if there are changes.
     */
    sync(name: string, options?: {
        force?: boolean;
        onlyWithChanges?: boolean;
    }): Promise<void>;
    /**
     * Starts the push process for a collection (sync process but only if there are changes)
     * @param name Name of the collection
     */
    pushChanges(name: string): Promise<void>;
    protected syncWithData(name: string, data: LoadResponse<ItemType>): Promise<void>;
}
export {};
