import { Ref, WatchSource, ShallowRef } from 'vue';

type Timer = ReturnType<typeof setTimeout> | undefined;
interface CacheData<D = any, p = any> {
    data: D;
    params: p;
    time: number;
}
interface CacheMapValue extends CacheData {
    timer: Timer;
}
type CachedKey = string;
declare const setCache: (key: CachedKey, value: CacheData, cacheTime: number) => void;
declare const getCache: (key: CachedKey) => CacheMapValue;
declare const clearCache: (key?: CachedKey | CachedKey[]) => void;

interface DebounceOptionsBase {
    leading?: boolean;
    trailing?: boolean;
    maxWait?: number;
}
interface ThrottleOptionsBase {
    leading?: boolean;
    trailing?: boolean;
}
type Params<P extends any[]> = Ref<P> | P | P[0] | Ref<P[0]>;
type MaybePromise<T> = T | Promise<T>;
interface Options<R, P extends any[]> {
    manual?: boolean;
    defaultData?: R | Ref<R>;
    defaultParams?: Params<P>;
    refreshDeps?: WatchSource<any>[] | WatchSource<any>;
    refreshDepsParams?: Params<P> | (() => void | Params<P>);
    retryCount?: number;
    retryInterval?: number;
    loadingDelay?: number;
    pollingInterval?: Ref<number> | number;
    pollingErrorRetryCount?: number;
    ready?: Ref<boolean> | boolean;
    debounceWait?: Ref<number> | number;
    debounceOptions?: Ref<DebounceOptionsBase> | DebounceOptionsBase;
    throttleWait?: Ref<number> | number;
    throttleOptions?: Ref<ThrottleOptionsBase> | ThrottleOptionsBase;
    cacheKey?: string | ((params?: P) => string);
    cacheTime?: number;
    staleTime?: number;
    getCache?: (cacheKey: string) => CacheData;
    setCache?: (cacheKey: string, cacheData: CacheData) => void;
    refreshOnWindowFocus?: Ref<boolean> | boolean;
    cancelOnWindowBlur?: Ref<boolean> | boolean;
    focusTimespan?: Ref<number> | number;
    onCache?: (response: R) => void;
    onBefore?: (params: P) => void;
    onRequest?: ({ params, response, error, abort }: {
        params: P;
        response: R;
        error: any;
        abort: boolean;
    }) => void;
    onSuccess?: (response: R, params: P) => MaybePromise<void | R>;
    onError?: (err: any, params: P) => void;
    onFinally?: () => void;
    onCancel?: () => void;
}
type PluginHooks<R, P extends unknown[]> = {
    onBefore: (params: P) => CallPlugin<R>['returnData'] | void;
    onInit: (service: () => Promise<R>) => () => Promise<R>;
    onSuccess(data: R, params: P): void;
    onError(error: Error, params: P): void;
    onFinally(params: P, data: R, error: Error): void;
    onCancel(): void;
    onMutate(data: R): void;
};
interface Instance<R, P extends unknown[]> extends State<R, P> {
    functionContext: FunctionContext<R, P>;
    plugins: Ref<Partial<PluginHooks<R, P>>[]>;
}
type Plugin<R, P extends unknown[]> = (instance: Instance<R, P>, options: Options<R, P>) => Partial<PluginHooks<R, P>>;
type State<R, P> = {
    status: Ref<'pending' | 'settled'>;
    data: Ref<R>;
    loading: Ref<boolean>;
    error: ShallowRef<any>;
    params: Ref<P>;
    pollingCount: Ref<number>;
    requestTick: (callback?: () => void) => Promise<unknown>;
};
type MutateData<R> = (newData: R) => void;
type MutateFunction<R> = (arg: (oldData: R) => R) => void;
interface Mutate<R> extends MutateData<R>, MutateFunction<R> {
}
type FunctionContext<R, P extends unknown[]> = {
    runAsync: (...arg: P) => Promise<R>;
    run: (...arg: P) => void;
    cancel: () => void;
    refresh: () => void;
    refreshAsync: () => Promise<R>;
    mutate: Mutate<R>;
};
interface Request<R, P extends unknown[]> extends State<R, P>, FunctionContext<R, P> {
}
type Service<R, P extends unknown[]> = (...args: P) => Promise<R>;
type CallPlugin<R> = {
    returnNow?: boolean;
    returnData?: any;
    returnType?: 'cache';
    servicePromise?: Promise<R>;
};

declare function debounce(func: (...args: any[]) => any, wait: number, options?: {
    leading?: boolean;
    trailing?: boolean;
    maxWait?: number;
}): {
    (this: any, ...args: any[]): any;
    cancel: () => void;
    flush: () => any;
    pending: () => boolean;
};

declare function throttle(func: (...args: any[]) => any, wait: number, options?: {
    leading?: boolean;
    trailing?: boolean;
    maxWait?: number;
}): {
    (this: any, ...args: any[]): any;
    cancel: () => void;
    flush: () => any;
    pending: () => boolean;
};

type Type = {
    isNull: (v: any) => boolean;
    isUndefined: (v: any) => boolean;
    isObject: (v: any) => boolean;
    isArray: (v: any) => boolean;
    isString: (v: any) => boolean;
    isNumber: (v: any) => boolean;
    isBoolean: (v: any) => boolean;
    isFunction: (v: any) => boolean;
    isRegExp: (v: any) => boolean;
    isPromise: (v: any) => boolean;
};

declare const TypeChecker: Type;

declare const trigger: (key: string, data: any) => void;

declare function definePlugins(plugins: Plugin<any, any[]>[]): void;
declare function useRequest<R, P extends unknown[] = any>(service: Service<R, P>, options?: Options<R, P>, plugins?: Plugin<R, P>[]): Request<R, P>;

export { TypeChecker, clearCache, debounce, definePlugins, getCache, setCache, throttle, trigger, useRequest };
