import { DeferredSequence } from "../sequence/DeferredSequence.js";
import { NONE, SKIP } from "../util/constants.js";
import type { AnyCaller, Arguments, Callback, ErrorCallback, ValueCallback } from "../util/function.js";
import { type PossibleStarter, type StopCallback } from "../util/start.js";
/** Any `Store` instance. */
export type AnyStore = Store<any, any>;
/** Values that a store natively knows how to process as inputs. */
export type StoreInput<I> = I | typeof SKIP | typeof NONE;
/** Values that a store natively knows how to process as inputs. */
export type AsyncStoreInput<I> = StoreInput<I> | PromiseLike<StoreInput<I>>;
/** Internal storage value for a store. */
export type StoreInternal<O> = O | typeof NONE;
/** Callback that sets a store's value (possibly asynchronously). */
export type StoreCallback<I, A extends Arguments = []> = (...args: A) => AsyncStoreInput<I>;
/** Reducer that receives a store's current value and sets the stores next value (possibly asynchronously). */
export type StoreReducer<I, O, A extends Arguments = []> = (value: O, ...args: A) => AsyncStoreInput<I>;
/**
 * Store that retains its most recent value and is async-iterable to allow values to be observed.
 * - Current value can be read at `store.value` and `store.data`
 * - Stores also send their most-recent value to any new subscribers immediately when a new subscriber is added.
 * - Stores can also be in a loading store where they do not have a current value.
 *
 * @param initial The initial value for this store, a `Promise` that resolves to the initial value, a source `Subscribable` to subscribe to, or another `Store` instance to take the initial value from and subscribe to.
 * - To set this store to be loading, use the `NONE` constant or a `Promise` value.
 * - To set this store to an explicit value, use that value or another `Store` instance with a value.
 *
 * @param T The "main type" for this store.
 * - Indicates what values `this.value` will return.
 * - Methods that set values like `this.call()` and `this.await()` can also accept these values.
 * @param TT The "input type" for this store.
 * - Indicates what additional input types `this.value` can convert to `T`
 * - Defaults to `T` (no conversion).
 * - Override conversion by overriding `this._convert(v: TT): T`
 * - Warning: With no override, default behaviour is to just assert TT is T (unsafe).
 */
export declare class Store<T, TT = T> implements AsyncIterable<T, void, void>, AsyncDisposable {
    /** Deferred sequence this store uses to issue values as they change. */
    readonly next: DeferredSequence<T, void, void>;
    /**
     * Snapshot returns either the current reason or the current value (or `NONE` if reason is unset).
     */
    get snapshot(): unknown;
    /**
     * Store is considered to be "loading" if it has no value or error.
     * - Calling `this.value` will throw `this.reason` if there's an error reason set, or a `Promise` if there's no value set.
     * - Calling `this.loading` is a way to check if this store has a value without triggering those throws.
     */
    get loading(): boolean;
    /**
     * Set the value of this store.
     * - Sets any sync values.
     * - Awaits any async values.
     * - Setting value the `NONE` symbol indicates the store has no value so should be in a "loading" state.
     * - Setting value to `SKIP` indicates the value should be silently ignored (sometimes it's helpful to have a way to skip a write entirely).
     * - Setting value to the same as the existing value
     * - If this store has any pending `await()` calls they are aborted and their results are silently discarded.
     */
    set value(input: AsyncStoreInput<TT>);
    /** Write a synchronous value to this store. */
    write(input: StoreInput<TT>): void;
    /**
     * Convert input type to internal storage type.
     * - Override in subclasses to change conversion behaviour.
     * - Warning: With no override, default behaviour is to just assert TT is T (unsafe).
     */
    protected _convert(input: TT, _caller?: AnyCaller): T;
    /** Compare two values for this store and return whether they are equal. */
    protected _equal(a: T, b: T): boolean;
    /** Internal storage for current value. */
    private _value;
    /**
     * Get the current value of this store.
     *
     * @throws {Promise} if this store currently is in a "loading" state (resolves when a value is set).
     * @throws {unknown} if this store currently has an error.
     */
    get value(): T;
    /**
     * Called to read values. Can be used to override get behaviour.
     * - Override in subclasses to change getting behaviour.
     * - Note: doesn't throw `reason` if there is one!
     */
    read(): StoreInternal<T>;
    /**
     * Time (in milliseconds) this store was last updated with a new value.
     * - Will be `undefined` if the value is still loading.
     */
    get time(): number | undefined;
    private _time;
    /**
     * How old this store's value is (in milliseconds).
     * - Will be `Infinity` if the value is still loading (to simplify downstream calculations).
     *
     * @example if (store.age > MINUTE) refreshStore(store);
     */
    get age(): number;
    /**
     * Whether this store is stale based on a `maxAge` value in milliseconds.
     *
     * @param maxAge The maximum age for the stale check.
     * - `0` zero means "always refresh" (this is the default).
     * - `Infinity` means "refresh only if store is still in a loading state"
     * - Any other value may or may not be stale based on `this.age`
     */
    stale(maxAge: number): boolean;
    /** Current error of this store, or `undefined` if there is no error. */
    get reason(): unknown;
    set reason(reason: unknown);
    private _reason;
    /**
     * Set a starter for this store to allow a function to execute when this store has subscribers or not.
     *
     * @todo DH: Change this significantly. Not happy with how it's settable like this. It should be set in `constructor()`?
     *  - Also would love some internal hooks
     */
    protected set starter(start: PossibleStarter<[this]>);
    private _starter;
    /** Store is initiated with a value, or `NONE` to put it in a "loading" state. */
    constructor(value: StoreInternal<T>);
    /** Set the value of this store as values are pulled from a sequence. */
    through(sequence: AsyncIterable<TT>): AsyncIterable<TT>;
    /**
     * Call a callback and save the returned value to this store.
     * - If the callback returns an async value, it is awaited and values/errors will be saved.
     */
    call<A extends Arguments>(callback: StoreCallback<TT, A>, ...args: A): Promise<boolean> | boolean;
    /**
     * Send the current value to a callback and save the returned value to this store.
     * - If the callback returns an async value, it is awaited and values/errors will be saved.
     */
    reduce<A extends Arguments>(reducer: StoreReducer<TT, T, A>, ...args: A): Promise<boolean> | boolean;
    /**
     * Run a callback and ignore any returned value.
     * - If the callback returns an async value, it is awaited and errors will be saved.
     */
    run<A extends Arguments>(callback: (...args: A) => void, ...args: A): Promise<boolean> | boolean;
    /**
     * Send the current value to a callback and ignore any returned value.
     * - If the callback returns an async value, it is awaited and errors will be saved.
     */
    send<A extends Arguments>(callback: (value: T, ...args: A) => void, ...args: A): Promise<boolean> | boolean;
    /**
     * Await an async value and save it to this store.
     * - Saves the resolved value.
     * - If it rejects saves the rejection as `reason`.
     * - Silently discarded if a newer value is set.
     * - Silently discarded if `await()` is called again.
     * - Silently discarded if `abort()` is called.
     *
     * @param pending The pending value to await.
     *
     * @returns {true} If the callback returned a value and it was set.
     * @returns {false} If the callback threw.
     * @returns {Promise<true>} If the callback returned a promise and it resolved.
     * @returns {Promise<false>} If the callback returned a promise and it rejected, or `abort()` was called before it resolved.
     *
     * @throws {never} Never throws — safe to call without handling the return value.
     */
    await(pending: PromiseLike<StoreInput<TT>>): Promise<boolean>;
    private _pendingValue;
    /**
     * Abort any current pending `await()` call.
     * - The pending call's result will be silently discarded and its error will not be stored.
     */
    abort(): void;
    [Symbol.asyncIterator](): AsyncIterator<T, void, void>;
    private _iterating;
    [Symbol.asyncDispose](): Promise<void>;
    /**
     * Subscribe to this store with handlers.
     * - Returns a `StopCallback` to stop the subscription.
     */
    subscribe(onNext?: ValueCallback<T>, onError?: ErrorCallback, onReturn?: Callback): StopCallback;
}
