import * as _axios from 'axios';
import { AxiosRequestConfig, CreateAxiosDefaults, Axios, AxiosInterceptorManager, InternalAxiosRequestConfig, AxiosResponse } from 'axios';
import { Fn } from '@wang-yige/utils';

declare enum SingleType {
    /**
     * Always use the next request,
     * and if the prev request is not finished, it will be aborted.
     */
    NEXT = "next",
    /**
     * Always use the prev request,
     * and if current request is not finished, the latest request will be aborted.
     */
    PREV = "prev",
    /**
     * If the prev request is not finished, the latest request will be added to the queue.
     * - Default value
     */
    QUEUE = "queue"
}

interface InitialConfig {
	/**
	 * The maximum number of requests sent at the same time.
	 * - default `5`
	 */
	maximumInOneTime?: number;
	/**
	 * The limit number of requests sent in one second, if exceed, it will throw an axios CanceledError.
	 * If pass in zero or negative, it will not have any restrictions set.
	 * - default `50`
	 */
	limitInOneSecond?: number;
}

interface Single {
	/**
	 * The type for single request.
	 * - default is `SingleType.QUEUE`
	 */
	type?: SingleType;
}

interface Cache {
	/**
	 * Cache time in miliseconds.
	 * If time is zero, it will not be cached.
	 * If time is negative, it will not clear cache.
	 * - default `-1`
	 */
	time?: number;
}

type CodeRange = { from: number; to: number };

type RetryCodeRange = number | number[] | CodeRange | Array<CodeRange> | string;

interface Retry {
	/**
	 * Retry count.
	 * - default `5`
	 */
	count?: number;
	/**
	 * Delay time for retry in miliseconds.
	 * - default `1000`
	 */
	delay?: number;
	/**
	 * The axios error reasons to retry.
	 * - default `['ECONNABORTED', 'ERR_NETWORK, 'ETIMEDOUT', 'ECONNREFUSED']`
	 * `'ECONNREFUSED'` is only available in nodejs.
	 */
	errorReasons?: string | string[];
	/**
	 * If `retry.errorReasons` not include `ERR_BAD_RESPONSE`,
	 * this config will be matched when response `err.code` equals `ERR_BAD_RESPONSE`.
	 * - default codes are `500`, `404`, `502`
	 */
	badResponseCodes?: RetryCodeRange;
	/**
	 * If `retry.` not include `ERR_BAD_REQUEST`,
	 * this config will be matched when response `err.code` equals `ERR_BAD_REQUEST`.
	 * - default code is `404`
	 */
	badRequestCodes?: RetryCodeRange;
	/**
	 * The domains that can be retried.
	 */
	domains?: string[];
}

interface CustomConfig {
	/**
	 * The same url request is only single at a time.
	 * Not include the params.
	 * - default `true`
	 */
	single?: boolean | Single;
	/**
	 * Cache the `Get` request response.
	 * - default `false`
	 */
	cache?: boolean | Cache;
	/**
	 * Retry the request if failed.
	 * - default `false`
	 */
	retry?: boolean | Retry;
}

type RequestConfig<D = any> = AxiosRequestConfig<D> & CustomConfig & { [K in string]: any };

type RequestPromise<T = any> = Promise<T> & {
	/**
	 * Abort the request.
	 */
	abort: Fn;
	/**
	 * alias of `abort` method.
	 */
	cancel: Fn;
};

declare const noDataMethods: readonly ["get", "delete", "head", "options"];
declare const withDataMethods: readonly ["post", "put", "patch", "postForm", "putForm", "patchForm"];
declare class AxiosRequestInstance {
    /** The data of single types */
    static Single: typeof SingleType;
    static create(config?: InitialConfig & CreateAxiosDefaults): AxiosRequestInstance;
    static create(baseURL?: string, config?: InitialConfig & Omit<CreateAxiosDefaults, 'baseURL'>): AxiosRequestInstance;
    private _maximum;
    private _axios;
    private _pipeline;
    private _frequency;
    private requestInterceptor;
    private requestInterceptorIndex;
    private responseInterceptorIndex;
    private cacheController;
    private singleController;
    constructor(config?: InitialConfig & CreateAxiosDefaults);
    constructor(baseURL?: string, config?: InitialConfig & Omit<CreateAxiosDefaults, 'baseURL'>);
    get defaults(): _axios.AxiosDefaults<any>;
    /**
     * Current axios instance, with don't have wrapper methods
     */
    get axios(): Axios;
    /**
     * Axios static object
     */
    get Axios(): _axios.AxiosStatic;
    private _interceptors;
    /**
     * Request interceptor
     */
    get interceptors(): {
        request: AxiosInterceptorManager<InternalAxiosRequestConfig>;
        response: AxiosInterceptorManager<AxiosResponse>;
    };
    /**
     * Change the maximum number of parallel requests pipeline.
     */
    maximum(maximum: number): void;
    getUri(config?: RequestConfig): string;
    private proxy;
    get<T = any, R = AxiosResponse<T>, D = any>(url: string, config?: RequestConfig<D>): RequestPromise<R>;
    delete<T = any, R = AxiosResponse<T>, D = any>(url: string, config?: RequestConfig<D>): RequestPromise<R>;
    head<T = any, R = AxiosResponse<T>, D = any>(url: string, config?: RequestConfig<D>): RequestPromise<R>;
    options<T = any, R = AxiosResponse<T>, D = any>(url: string, config?: RequestConfig<D>): RequestPromise<R>;
    post<T = any, R = AxiosResponse<T>, D = any>(url: string, data?: D, config?: RequestConfig<D>): RequestPromise<R>;
    put<T = any, R = AxiosResponse<T>, D = any>(url: string, data?: D, config?: RequestConfig<D>): RequestPromise<R>;
    patch<T = any, R = AxiosResponse<T>, D = any>(url: string, data?: D, config?: RequestConfig<D>): RequestPromise<R>;
    postForm<T = any, R = AxiosResponse<T>, D = any>(url: string, data?: D, config?: RequestConfig<D>): RequestPromise<R>;
    putForm<T = any, R = AxiosResponse<T>, D = any>(url: string, data?: D, config?: RequestConfig<D>): RequestPromise<R>;
    patchForm<T = any, R = AxiosResponse<T>, D = any>(url: string, data?: D, config?: RequestConfig<D>): RequestPromise<R>;
}
type AxiosRequestStatic = typeof AxiosRequestInstance & Pick<AxiosRequestInstance, (typeof noDataMethods)[number] | (typeof withDataMethods)[number]>;
/** A wrapper of `Axios` */
declare const AxiosRequest: AxiosRequestStatic;
/** alias of `AxiosRequest` */
declare const APIRequest: AxiosRequestStatic;
/** The origin axios static object */
declare const axios: _axios.AxiosStatic;

export { APIRequest, AxiosRequest, axios };
