import { Store } from '@tanstack/store';
import { Transaction } from './transactions.js';
import { SortedMap } from './SortedMap.js';
import { ChangeListener, ChangeMessage, CollectionConfig, Fn, InsertConfig, OperationConfig, Transaction as TransactionType, UtilsRecord } from './types.js';
export declare const collectionsStore: Map<string, CollectionImpl<any, any>>;
/**
 * Enhanced Collection interface that includes both data type T and utilities TUtils
 * @template T - The type of items in the collection
 * @template TUtils - The utilities record type
 */
export interface Collection<T extends object = Record<string, unknown>, TKey extends string | number = string | number, TUtils extends UtilsRecord = {}> extends CollectionImpl<T, TKey> {
    readonly utils: TUtils;
}
/**
 * Creates a new Collection instance with the given configuration
 *
 * @template T - The type of items in the collection
 * @template TKey - The type of the key for the collection
 * @template TUtils - The utilities record type
 * @param options - Collection options with optional utilities
 * @returns A new Collection with utilities exposed both at top level and under .utils
 */
export declare function createCollection<T extends object = Record<string, unknown>, TKey extends string | number = string | number, TUtils extends UtilsRecord = {}>(options: CollectionConfig<T, TKey> & {
    utils?: TUtils;
}): Collection<T, TKey, TUtils>;
/**
 * Preloads a collection with the given configuration
 * Returns a promise that resolves once the sync tool has done its first commit (initial sync is finished)
 * If the collection has already loaded, it resolves immediately
 *
 * This function is useful in route loaders or similar pre-rendering scenarios where you want
 * to ensure data is available before a route transition completes. It uses the same shared collection
 * instance that will be used by useCollection, ensuring data consistency.
 *
 * @example
 * ```typescript
 * // In a route loader
 * async function loader({ params }) {
 *   await preloadCollection({
 *     id: `users-${params.userId}`,
 *     sync: { ... },
 *   });
 *
 *   return null;
 * }
 * ```
 *
 * @template T - The type of items in the collection
 * @param config - Configuration for the collection, including id and sync
 * @returns Promise that resolves when the initial sync is finished
 */
export declare function preloadCollection<T extends object = Record<string, unknown>, TKey extends string | number = string | number>(config: CollectionConfig<T, TKey>): Promise<CollectionImpl<T, TKey>>;
/**
 * Custom error class for schema validation errors
 */
export declare class SchemaValidationError extends Error {
    type: `insert` | `update`;
    issues: ReadonlyArray<{
        message: string;
        path?: ReadonlyArray<string | number | symbol>;
    }>;
    constructor(type: `insert` | `update`, issues: ReadonlyArray<{
        message: string;
        path?: ReadonlyArray<string | number | symbol>;
    }>, message?: string);
}
export declare class CollectionImpl<T extends object = Record<string, unknown>, TKey extends string | number = string | number> {
    transactions: SortedMap<string, Transaction<any>>;
    syncedData: Map<TKey, T>;
    syncedMetadata: Map<TKey, unknown>;
    derivedUpserts: Map<TKey, T>;
    derivedDeletes: Set<TKey>;
    private _size;
    private changeListeners;
    private changeKeyListeners;
    utils: Record<string, Fn>;
    private pendingSyncedTransactions;
    private syncedKeys;
    config: CollectionConfig<T, TKey>;
    private hasReceivedFirstCommit;
    private onFirstCommitCallbacks;
    /**
     * Register a callback to be executed on the next commit
     * Useful for preloading collections
     * @param callback Function to call after the next commit
     */
    onFirstCommit(callback: () => void): void;
    id: string;
    /**
     * Creates a new Collection instance
     *
     * @param config - Configuration object for the collection
     * @throws Error if sync config is missing
     */
    constructor(config: CollectionConfig<T, TKey>);
    /**
     * Recompute optimistic state from active transactions
     */
    private recomputeOptimisticState;
    /**
     * Calculate the current size based on synced data and optimistic changes
     */
    private calculateSize;
    /**
     * Collect events for optimistic changes
     */
    private collectOptimisticChanges;
    /**
     * Get the previous value for a key given previous optimistic state
     */
    private getPreviousValue;
    /**
     * Emit multiple events at once to all listeners
     */
    private emitEvents;
    /**
     * Get the current value for a key (virtual derived state)
     */
    get(key: TKey): T | undefined;
    /**
     * Check if a key exists in the collection (virtual derived state)
     */
    has(key: TKey): boolean;
    /**
     * Get the current size of the collection (cached)
     */
    get size(): number;
    /**
     * Get all keys (virtual derived state)
     */
    keys(): IterableIterator<TKey>;
    /**
     * Get all values (virtual derived state)
     */
    values(): IterableIterator<T>;
    /**
     * Get all entries (virtual derived state)
     */
    entries(): IterableIterator<[TKey, T]>;
    /**
     * Attempts to commit pending synced transactions if there are no active transactions
     * This method processes operations from pending transactions and applies them to the synced data
     */
    commitPendingTransactions: () => void;
    private ensureStandardSchema;
    getKeyFromItem(item: T): TKey;
    generateGlobalKey(key: any, item: any): string;
    private validateData;
    /**
     * Inserts one or more items into the collection
     * @param items - Single item or array of items to insert
     * @param config - Optional configuration including metadata and custom keys
     * @returns A TransactionType object representing the insert operation(s)
     * @throws {SchemaValidationError} If the data fails schema validation
     * @example
     * // Insert a single item
     * insert({ text: "Buy groceries", completed: false })
     *
     * // Insert multiple items
     * insert([
     *   { text: "Buy groceries", completed: false },
     *   { text: "Walk dog", completed: false }
     * ])
     *
     * // Insert with custom key
     * insert({ text: "Buy groceries" }, { key: "grocery-task" })
     */
    insert: (data: T | Array<T>, config?: InsertConfig) => Transaction<Record<string, unknown>>;
    /**
     * Updates one or more items in the collection using a callback function
     * @param items - Single item/key or array of items/keys to update
     * @param configOrCallback - Either update configuration or update callback
     * @param maybeCallback - Update callback if config was provided
     * @returns A Transaction object representing the update operation(s)
     * @throws {SchemaValidationError} If the updated data fails schema validation
     * @example
     * // Update a single item
     * update(todo, (draft) => { draft.completed = true })
     *
     * // Update multiple items
     * update([todo1, todo2], (drafts) => {
     *   drafts.forEach(draft => { draft.completed = true })
     * })
     *
     * // Update with metadata
     * update(todo, { metadata: { reason: "user update" } }, (draft) => { draft.text = "Updated text" })
     */
    /**
     * Updates one or more items in the collection using a callback function
     * @param ids - Single ID or array of IDs to update
     * @param configOrCallback - Either update configuration or update callback
     * @param maybeCallback - Update callback if config was provided
     * @returns A Transaction object representing the update operation(s)
     * @throws {SchemaValidationError} If the updated data fails schema validation
     * @example
     * // Update a single item
     * update("todo-1", (draft) => { draft.completed = true })
     *
     * // Update multiple items
     * update(["todo-1", "todo-2"], (drafts) => {
     *   drafts.forEach(draft => { draft.completed = true })
     * })
     *
     * // Update with metadata
     * update("todo-1", { metadata: { reason: "user update" } }, (draft) => { draft.text = "Updated text" })
     */
    update<TItem extends object = T>(key: Array<TKey | unknown>, callback: (drafts: Array<TItem>) => void): TransactionType;
    update<TItem extends object = T>(keys: Array<TKey | unknown>, config: OperationConfig, callback: (drafts: Array<TItem>) => void): TransactionType;
    update<TItem extends object = T>(id: TKey | unknown, callback: (draft: TItem) => void): TransactionType;
    update<TItem extends object = T>(id: TKey | unknown, config: OperationConfig, callback: (draft: TItem) => void): TransactionType;
    /**
     * Deletes one or more items from the collection
     * @param ids - Single ID or array of IDs to delete
     * @param config - Optional configuration including metadata
     * @returns A TransactionType object representing the delete operation(s)
     * @example
     * // Delete a single item
     * delete("todo-1")
     *
     * // Delete multiple items
     * delete(["todo-1", "todo-2"])
     *
     * // Delete with metadata
     * delete("todo-1", { metadata: { reason: "completed" } })
     */
    delete: (keys: Array<TKey> | TKey, config?: OperationConfig) => TransactionType<any>;
    /**
     * Gets the current state of the collection as a Map
     *
     * @returns A Map containing all items in the collection, with keys as identifiers
     */
    get state(): Map<TKey, T>;
    /**
     * Gets the current state of the collection as a Map, but only resolves when data is available
     * Waits for the first sync commit to complete before resolving
     *
     * @returns Promise that resolves to a Map containing all items in the collection
     */
    stateWhenReady(): Promise<Map<TKey, T>>;
    /**
     * Gets the current state of the collection as an Array
     *
     * @returns An Array containing all items in the collection
     */
    get toArray(): T[];
    /**
     * Gets the current state of the collection as an Array, but only resolves when data is available
     * Waits for the first sync commit to complete before resolving
     *
     * @returns Promise that resolves to an Array containing all items in the collection
     */
    toArrayWhenReady(): Promise<Array<T>>;
    /**
     * Returns the current state of the collection as an array of changes
     * @returns An array of changes
     */
    currentStateAsChanges(): Array<ChangeMessage<T>>;
    /**
     * Subscribe to changes in the collection
     * @param callback - A function that will be called with the changes in the collection
     * @returns A function that can be called to unsubscribe from the changes
     */
    subscribeChanges(callback: (changes: Array<ChangeMessage<T>>) => void, { includeInitialState }?: {
        includeInitialState?: boolean;
    }): () => void;
    /**
     * Subscribe to changes for a specific key
     */
    subscribeChangesKey(key: TKey, listener: ChangeListener<T, TKey>, { includeInitialState }?: {
        includeInitialState?: boolean;
    }): () => void;
    /**
     * Trigger a recomputation when transactions change
     * This method should be called by the Transaction class when state changes
     */
    onTransactionStateChange(): void;
    private _storeMap;
    /**
     * Returns a Tanstack Store Map that is updated when the collection changes
     * This is a temporary solution to enable the existing framework hooks to work
     * with the new internals of Collection until they are rewritten.
     * TODO: Remove this once the framework hooks are rewritten.
     */
    asStoreMap(): Store<Map<TKey, T>>;
    private _storeArray;
    /**
     * Returns a Tanstack Store Array that is updated when the collection changes
     * This is a temporary solution to enable the existing framework hooks to work
     * with the new internals of Collection until they are rewritten.
     * TODO: Remove this once the framework hooks are rewritten.
     */
    asStoreArray(): Store<Array<T>>;
}
