import { Status, RunEffect } from './enums.js';

interface BaseSource<TData, TArgs extends unknown[], TError> {
    key: string;
    uniqueId: number;
    readonly inst: StateInterface<TData, TArgs, TError>;
    getVersion(): number;
    getPayload(): Record<string, unknown>;
    mergePayload(partialPayload?: Record<string, unknown>): void;
    getState(): State<TData, TArgs, TError>;
    setState(value: StateFunctionUpdater<TData, TArgs, TError> | TData, status: "initial", callbacks?: ProducerCallbacks<TData, TArgs, TError>): void;
    setState(value: null, status: "pending", callbacks?: ProducerCallbacks<TData, TArgs, TError>): void;
    setState(value: TError, status: "error", callbacks?: ProducerCallbacks<TData, TArgs, TError>): void;
    setState(value: StateFunctionUpdater<TData, TArgs, TError> | TData, status?: "success", callbacks?: ProducerCallbacks<TData, TArgs, TError>): void;
    setData(newData: TData | ((prevData: TData | null) => TData)): void;
    replaceState(newState: State<TData, TArgs, TError>, notify?: boolean, callbacks?: ProducerCallbacks<TData, TArgs, TError>): void;
    subscribe(cb: (s: State<TData, TArgs, TError>) => void): AbortFn;
    subscribe(subProps: AsyncStateSubscribeProps<TData, TArgs, TError>): AbortFn;
    subscribe(argv: ((s: State<TData, TArgs, TError>) => void) | AsyncStateSubscribeProps<TData, TArgs, TError>): AbortFn;
    replay(): AbortFn;
    abort(reason?: any): void;
    replaceProducer(newProducer: Producer<TData, TArgs, TError> | null): void;
    invalidateCache(cacheKey?: string): void;
    replaceCache(cacheKey: string, cache: CachedState<TData, TArgs, TError>): void;
    patchConfig(partialConfig?: Partial<ProducerConfig<TData, TArgs, TError>>): void;
    patchConfig(updater?: (config: Partial<ProducerConfig<TData, TArgs, TError>>) => Partial<ProducerConfig<TData, TArgs, TError>>): void;
    patchConfig(updater?: Partial<ProducerConfig<TData, TArgs, TError>> | ((config: Partial<ProducerConfig<TData, TArgs, TError>>) => Partial<ProducerConfig<TData, TArgs, TError>>)): void;
    getConfig(): ProducerConfig<TData, TArgs, TError>;
    on(eventType: InstanceChangeEvent, eventHandler: InstanceChangeEventHandlerType<TData, TArgs, TError>): () => void;
    on(eventType: InstanceDisposeEvent, eventHandler: InstanceDisposeEventHandlerType<TData, TArgs, TError>): () => void;
    on(eventType: InstanceCacheChangeEvent, eventHandler: InstanceCacheChangeEventHandlerType<TData, TArgs, TError>): () => void;
    dispose(): boolean;
}
type StateChangeEventHandler<TData, TArgs extends unknown[], TError> = ((newState: State<TData, TArgs, TError>) => void) | InstanceChangeEventObject<TData, TArgs, TError>;
type InstanceChangeEventObject<TData, TArgs extends unknown[], TError> = {
    status: Status;
    handler: (newState: State<TData, TArgs, TError>) => void;
};
type InstanceChangeEventHandlerType<TData, TArgs extends unknown[], TError> = StateChangeEventHandler<TData, TArgs, TError> | StateChangeEventHandler<TData, TArgs, TError>[];
type InstanceDisposeEventHandlerType<TData, TArgs extends unknown[], TError> = (() => void) | (() => void)[];
type InstanceCacheChangeEventHandlerType<TData, TArgs extends unknown[], TError> = ((cache: Record<string, CachedState<TData, TArgs, TError>> | null | undefined) => void) | ((cache: Record<string, CachedState<TData, TArgs, TError>> | null | undefined) => void)[];
type InstanceChangeEvent = "change";
type InstanceDisposeEvent = "dispose";
type InstanceCacheChangeEvent = "cache-change";
type AsyncStateSubscribeProps<TData, TArgs extends unknown[], TError> = {
    key?: string;
    flags?: number;
    cb(s: State<TData, TArgs, TError>): void;
};
type InstanceEvents<TData, TArgs extends unknown[], TError> = {
    change?: Record<number, InstanceChangeEventHandlerType<TData, TArgs, TError>>;
    dispose?: Record<number, InstanceDisposeEventHandlerType<TData, TArgs, TError>>;
    ["cache-change"]?: Record<number, InstanceCacheChangeEventHandlerType<TData, TArgs, TError>>;
};
type HydrationData<TData, TArgs extends unknown[], TError> = {
    state: State<TData, TArgs, TError>;
    payload: Record<string, unknown>;
    latestRun: RunTask<TData, TArgs, TError> | null;
};
interface PromiseLike<TData, TError> extends Promise<TData> {
    status: "pending" | "fulfilled" | "rejected";
    value?: TData;
    reason?: TError;
}
type HydratedState<TData, TArgs extends unknown[], TError> = InitialState<TData, TArgs> | PendingState<TData, TArgs, TError> | SuccessState<TData, TArgs> | ErrorState<TData, TArgs, TError>;
type SourceHydration<TData, TArgs extends unknown[], TError> = [
    HydratedState<TData, TArgs, TError>,
    RunTask<TData, TArgs, TError> | null,
    Record<string, any> | null
];
interface StateInterface<TData, TArgs extends unknown[], TError> {
    key: string;
    version: number;
    id: number;
    actions: Source<TData, TArgs, TError>;
    config: ProducerConfig<TData, TArgs, TError>;
    payload: Record<string, any> | null;
    state: State<TData, TArgs, TError>;
    lastSuccess: LastSuccessSavedState<TData, TArgs>;
    pendingUpdate: PendingUpdate | null;
    pendingTimeout: PendingTimeout | null;
    queue: UpdateQueue<TData, TArgs, TError> | null;
    subsIndex: number | null;
    subscriptions: Record<number, StateSubscription<TData, TArgs, TError>> | null;
    promise: PromiseLike<TData, TError> | null;
    res: {
        res: (data: TData) => void;
        rej: (error: TError) => void;
    } | null;
    fn: Producer<TData, TArgs, TError> | null;
    readonly ctx: LibraryContext | null;
    latestRun: RunTask<TData, TArgs, TError> | null;
    currentAbort: AbortFn | null;
    parent: StateInterface<TData, TArgs, TError> | null;
    lanes: Record<string, StateInterface<TData, TArgs, TError>> | null;
    cache: Record<string, CachedState<TData, TArgs, TError>> | null;
    events: InstanceEvents<TData, TArgs, TError> | null;
    eventsIndex: number | null;
    journal?: any[] | null;
    global: boolean | null;
}
interface RUNCProps<TData, TArgs extends unknown[], TError> extends ProducerCallbacks<TData, TArgs, TError> {
    args?: TArgs;
}
type LastSuccessSavedState<TData, TArgs extends unknown[]> = InitialState<TData, TArgs> | SuccessState<TData, TArgs>;
interface BaseState<TData, TArgs extends unknown[]> {
    data: TData;
    status: Status;
    timestamp: number;
    props: ProducerSavedProps<TData, TArgs>;
}
type SuccessState<TData, TArgs extends unknown[]> = {
    data: TData;
    timestamp: number;
    status: "success";
    props: ProducerSavedProps<TData, TArgs>;
};
type ErrorState<TData, TArgs extends unknown[], TError> = {
    data: TError;
    timestamp: number;
    status: "error";
    props: ProducerSavedProps<TData, TArgs>;
};
type PendingState<TData, TArgs extends unknown[], TError> = {
    data: null;
    timestamp: number;
    status: "pending";
    props: ProducerSavedProps<TData, TArgs>;
    prev: PendingPreviousState<TData, TArgs, TError>;
};
type PendingPreviousState<TData, TArgs extends unknown[], TError> = InitialState<TData, TArgs> | SuccessState<TData, TArgs> | ErrorState<TData, TArgs, TError>;
type InitialState<TData, TArgs extends unknown[]> = {
    timestamp: number;
    data: TData | undefined;
    status: "initial";
    props: ProducerSavedProps<TData, TArgs>;
};
type State<TData, TArgs extends unknown[], TError> = InitialState<TData, TArgs> | PendingState<TData, TArgs, TError> | SuccessState<TData, TArgs> | ErrorState<TData, TArgs, TError>;
type AbortFn = ((reason?: any) => void) | undefined;
type OnAbortFn<R = unknown> = (cb?: (reason?: R) => void) => void;
interface ProducerProps<TData, TArgs extends unknown[] = [], TError = Error> {
    onAbort: OnAbortFn;
    isAborted: () => boolean;
    abort: (reason?: any) => void;
    args: TArgs;
    signal: AbortSignal;
    payload: Record<string, unknown>;
    lastSuccess: LastSuccessSavedState<TData, TArgs>;
    emit(value: StateFunctionUpdater<TData, TArgs, TError> | TData, status: "initial"): void;
    emit(value: null, status: "pending"): void;
    emit(value: TError, status: "error"): void;
    emit(value: StateFunctionUpdater<TData, TArgs, TError> | TData, status?: "success"): void;
    getState: () => State<TData, TArgs, TError>;
}
type RunIndicators = {
    index: number;
    done: boolean;
    cleared: boolean;
    aborted: boolean;
};
type ProducerCallbacks<TData, TArgs extends unknown[], TError> = {
    onError?(errorState: ErrorState<TData, TArgs, TError>): void;
    onSuccess?(successState: SuccessState<TData, TArgs>): void;
};
type ProducerSavedProps<TData, TArgs extends unknown[]> = {
    args: TArgs;
    payload: Record<string, unknown> | null;
};
type Producer<TData, TArgs extends unknown[] = [], TError = Error> = (props: ProducerProps<TData, TArgs, TError>) => TData | Promise<TData>;
type ProducerFunction<TData, TArgs extends unknown[], TError> = (props: ProducerProps<TData, TArgs, TError>, runIndicators: RunIndicators, callbacks?: ProducerCallbacks<TData, TArgs, TError>) => AbortFn;
type ProducerConfig<TData, TArgs extends unknown[], TError> = {
    skipPendingStatus?: boolean;
    initialValue?: TData | ((cache: Record<string, CachedState<TData, TArgs, TError>> | null) => TData);
    cacheConfig?: CacheConfig<TData, TArgs, TError>;
    runEffectDurationMs?: number;
    runEffect?: RunEffect;
    keepPendingForMs?: number;
    skipPendingDelayMs?: number;
    resetStateOnDispose?: boolean;
    context?: unknown;
    hideFromDevtools?: boolean;
    retryConfig?: RetryConfig<TData, TArgs, TError>;
    storeInContext?: boolean;
};
type RetryConfig<TData, TArgs extends unknown[], TError> = {
    enabled: boolean;
    maxAttempts?: number;
    backoff?: number | ((attemptIndex: number, error: TError) => number);
    retry?: boolean | ((attemptIndex: number, error: TError) => boolean);
};
type StateFunctionUpdater<TData, TArgs extends unknown[], TError> = (updater: State<TData, TArgs, TError>) => TData;
type CreateSourceObject<TData, TArgs extends unknown[], TError> = {
    key: string;
    config?: ProducerConfig<TData, TArgs, TError>;
    producer?: Producer<TData, TArgs, TError> | null;
};
interface Source<TData, TArgs extends unknown[], TError> extends BaseSource<TData, TArgs, TError> {
    run(...args: TArgs): AbortFn;
    runp(...args: TArgs): Promise<State<TData, TArgs, TError>>;
    runc(props: RUNCProps<TData, TArgs, TError>): AbortFn;
    hasLane(laneKey: string): boolean;
    removeLane(laneKey?: string): boolean;
    getLane(laneKey?: string): Source<TData, TArgs, TError>;
    getAllLanes(): Source<TData, TArgs, TError>[];
}
type RunTask<TData, TArgs extends unknown[], TError> = {
    args: TArgs;
    payload: Record<string, unknown>;
};
type StateSubscription<TData, TArgs extends unknown[], TError> = {
    cleanup: () => void;
    props: AsyncStateSubscribeProps<TData, TArgs, TError>;
};
type OnCacheLoadProps<TData, TArgs extends unknown[], TError> = {
    cache: Record<string, CachedState<TData, TArgs, TError>>;
    source: Source<TData, TArgs, TError>;
};
type CacheConfig<TData, TArgs extends unknown[], TError> = {
    enabled: boolean;
    timeout?: ((currentState: State<TData, TArgs, TError>) => number) | number;
    hash?(args: TArgs | undefined, payload: Record<string, unknown> | null | undefined): string;
    auto?: boolean;
    persist?(cache: Record<string, CachedState<TData, TArgs, TError>>): void;
    load?(): Record<string, CachedState<TData, TArgs, TError>> | Promise<Record<string, CachedState<TData, TArgs, TError>>>;
    onCacheLoad?({ cache, source }: OnCacheLoadProps<TData, TArgs, TError>): void;
};
type CachedState<TData, TArgs extends unknown[], TError> = {
    state: State<TData, TArgs, TError>;
    addedAt: number;
    deadline: number;
    id?: ReturnType<typeof setTimeout>;
};
type PendingTimeout = {
    id: ReturnType<typeof setTimeout>;
    at: number;
};
type PendingUpdate = {
    id: ReturnType<typeof setTimeout>;
    callback(): void;
};
type SetStateUpdateQueue<TData, TArgs extends unknown[], TError> = {
    id?: ReturnType<typeof setTimeout>;
    kind: 0;
    data: State<TData, TArgs, TError>;
    next: UpdateQueue<TData, TArgs, TError> | null;
    callbacks?: ProducerCallbacks<TData, TArgs, TError>;
};
type SetDataUpdateQueue<TData, TArgs extends unknown[], TError> = {
    id?: ReturnType<typeof setTimeout>;
    kind: 2;
    data: TData | ((prev: TData | null) => TData);
    next: UpdateQueue<TData, TArgs, TError> | null;
};
type ReplaceStateUpdateQueue<TData, TArgs extends unknown[], TError> = {
    id?: ReturnType<typeof setTimeout>;
    kind: 1;
    data: {
        status?: Status;
        data: TData | StateFunctionUpdater<TData, TArgs, TError>;
    };
    next: UpdateQueue<TData, TArgs, TError> | null;
    callbacks?: ProducerCallbacks<TData, TArgs, TError>;
};
type UpdateQueue<TData, TArgs extends unknown[], TError> = ReplaceStateUpdateQueue<TData, TArgs, TError> | SetStateUpdateQueue<TData, TArgs, TError> | SetDataUpdateQueue<TData, TArgs, TError>;
type LibraryContext = {
    ctx: any;
    name?: string;
    terminate(): void;
    payload: Record<string, any>;
    remove(key: string): boolean;
    getAll(): StateInterface<any, any, any>[];
    get(key: string): StateInterface<any, any, any> | undefined;
    set(key: string, inst: StateInterface<any, any, any>): void;
};

export { AbortFn, AsyncStateSubscribeProps, BaseSource, BaseState, CacheConfig, CachedState, CreateSourceObject, ErrorState, HydrationData, InitialState, InstanceCacheChangeEvent, InstanceCacheChangeEventHandlerType, InstanceChangeEvent, InstanceChangeEventHandlerType, InstanceChangeEventObject, InstanceDisposeEvent, InstanceDisposeEventHandlerType, InstanceEvents, LastSuccessSavedState, LibraryContext, OnAbortFn, OnCacheLoadProps, PendingPreviousState, PendingState, PendingTimeout, PendingUpdate, Producer, ProducerCallbacks, ProducerConfig, ProducerFunction, ProducerProps, ProducerSavedProps, PromiseLike, RUNCProps, ReplaceStateUpdateQueue, RetryConfig, RunIndicators, RunTask, SetDataUpdateQueue, SetStateUpdateQueue, Source, SourceHydration, State, StateChangeEventHandler, StateFunctionUpdater, StateInterface, StateSubscription, SuccessState, UpdateQueue };
