import CallableInstance from 'callable-instance';
import { Awaitable } from 'cosmokit';
export { fetch } from 'ofetch';

declare class FexiosResponse<T = any> {
    rawResponse: Response;
    data: T;
    ok: boolean;
    status: number;
    statusText: string;
    headers: Headers;
    constructor(rawResponse: Response, data: T, overrides?: Partial<Omit<FexiosResponse<T>, 'rawResponse' | 'data'>>);
}

interface FexiosConfigs {
    baseURL: string;
    timeout: number;
    query: Record<string, string | number | boolean> | URLSearchParams;
    headers: Record<string, string> | Headers;
    credentials?: RequestInit['credentials'];
    cache?: RequestInit['cache'];
    mode?: RequestInit['mode'];
    responseType?: 'json' | 'blob' | 'text' | 'stream';
}
interface FexiosRequestOptions extends FexiosConfigs {
    url?: string | URL;
    method?: FexiosMethods;
    body?: Record<string, any> | string | FormData | URLSearchParams;
    abortController?: AbortController;
    onProgress?: (progress: number, chunk?: Uint8Array, buffer?: Uint8Array) => void;
}
interface FexiosContext<T = any> extends FexiosRequestOptions {
    url: string;
    rawRequest?: Request;
    rawResponse?: Response;
    response?: FexiosResponse;
    data?: T;
}
type FexiosFinalContext<T = any> = Omit<FexiosContext<T>, 'rawResponse' | 'response' | 'data' | 'headers'> & {
    rawResponse: Response;
    response: FexiosResponse<T>;
    headers: Headers;
    data: T;
};
type FexiosHook<C = unknown> = (context: C) => Awaitable<C | false>;
interface FexiosHookStore {
    event: FexiosLifecycleEvents;
    action: FexiosHook;
}
type FexiosLifecycleEvents = 'beforeInit' | 'beforeRequest' | 'afterBodyTransformed' | 'beforeActualFetch' | 'afterResponse';
interface FexiosHooksNameMap {
    beforeInit: FexiosContext;
    beforeRequest: FexiosContext;
    afterBodyTransformed: FexiosContext;
    beforeActualFetch: FexiosContext;
    afterResponse: FexiosFinalContext;
}
interface FexiosInterceptor {
    handlers: () => FexiosHook[];
    use: <C = FexiosContext>(hook: FexiosHook<C>, prepend?: boolean) => Fexios;
    clear: () => void;
}
interface FexiosInterceptors {
    request: FexiosInterceptor;
    response: FexiosInterceptor;
}
type LowerAndUppercase<T extends string> = Lowercase<T> | Uppercase<T>;
type FexiosMethods = LowerAndUppercase<'get' | 'post' | 'put' | 'patch' | 'delete' | 'head' | 'options' | 'trace'>;
type MethodsWithoutBody = LowerAndUppercase<'get' | 'head' | 'options' | 'trace'>;
type FexiosRequestShortcut<M extends FexiosMethods> = M extends MethodsWithoutBody ? ShortcutWithoutBody : ShortcutWithBody;
type ShortcutWithoutBody = <T = any>(url: string | URL, options?: Partial<FexiosRequestOptions>) => Promise<FexiosFinalContext<T>>;
type ShortcutWithBody = <T = any>(url: string | URL, body?: Record<string, any> | string | URLSearchParams | FormData | null, options?: Partial<FexiosRequestOptions>) => Promise<FexiosFinalContext<T>>;

declare enum FexiosErrorCodes {
    BODY_USED = "BODY_USED",
    NO_BODY_READER = "NO_BODY_READER",
    TIMEOUT = "TIMEOUT",
    NETWORK_ERROR = "NETWORK_ERROR",
    BODY_NOT_ALLOWED = "BODY_NOT_ALLOWED",
    HOOK_CONTEXT_CHANGED = "HOOK_CONTEXT_CHANGED",
    ABORTED_BY_HOOK = "ABORTED_BY_HOOK",
    INVALID_HOOK_CALLBACK = "INVALID_HOOK_CALLBACK",
    UNEXPECTED_HOOK_RETURN = "UNEXPECTED_HOOK_RETURN"
}
declare class FexiosError extends Error {
    readonly code: FexiosErrorCodes | string;
    readonly context?: FexiosContext | undefined;
    name: string;
    constructor(code: FexiosErrorCodes | string, message?: string, context?: FexiosContext | undefined, options?: ErrorOptions);
}
declare class FexiosResponseError<T> extends FexiosError {
    readonly response: FexiosResponse<T>;
    name: string;
    constructor(message: string, response: FexiosResponse<T>, options?: ErrorOptions);
}
/**
 * Check if the error is a FexiosError that not caused by Response error
 */
declare const isFexiosError: (e: any) => boolean;

/**
 * Fexios
 * @desc Fetch based HTTP client with similar API to axios for browser and Node.js
 *
 * @license MIT
 * @author dragon-fish <dragon-fish@qq.com>
 */
declare class Fexios extends CallableInstance<[
    string | URL | Partial<FexiosRequestOptions>,
    Partial<FexiosRequestOptions>?
], Promise<FexiosFinalContext>> {
    baseConfigs: Partial<FexiosConfigs>;
    protected hooks: FexiosHookStore[];
    readonly DEFAULT_CONFIGS: FexiosConfigs;
    private readonly ALL_METHODS;
    private readonly METHODS_WITHOUT_BODY;
    private static readonly BLOB_MIME_TYPE;
    constructor(baseConfigs?: Partial<FexiosConfigs>);
    request<T = any>(url: string | URL, options?: Partial<FexiosRequestOptions>): Promise<FexiosFinalContext<T>>;
    request<T = any>(options: Partial<FexiosRequestOptions> & {
        url: string | URL;
    }): Promise<FexiosFinalContext<T>>;
    mergeQuery(base: Record<string, any> | string | URLSearchParams | undefined, ...income: (Record<string, any> | string | URLSearchParams | undefined)[]): Record<string, any>;
    mergeHeaders(base: Record<string, any> | Headers | undefined, ...income: (Record<string, any> | Headers | undefined)[]): Record<string, any>;
    emit<C = FexiosContext>(event: FexiosLifecycleEvents, ctx: C): Promise<C>;
    on<C = FexiosContext>(event: FexiosLifecycleEvents, action: FexiosHook<C>, prepend?: boolean): this;
    off(event: FexiosLifecycleEvents, action: FexiosHook<any>): this;
    private createInterceptor;
    readonly interceptors: FexiosInterceptors;
    private createMethodShortcut;
    static resolveResponseBody<T = any>(rawResponse: Response, expectType?: FexiosConfigs['responseType'], onProgress?: (progress: number, chunk?: Uint8Array, buffer?: Uint8Array) => void): Promise<FexiosResponse<T>>;
    static isText(uint8Array: Uint8Array, maxBytesToCheck?: number): boolean;
    extends(configs: Partial<FexiosConfigs>): Fexios;
    readonly create: typeof Fexios.create;
    static create(configs?: Partial<FexiosConfigs>): Fexios;
}
interface Fexios {
    get: FexiosRequestShortcut<'get'>;
    post: FexiosRequestShortcut<'post'>;
    put: FexiosRequestShortcut<'put'>;
    patch: FexiosRequestShortcut<'patch'>;
    delete: FexiosRequestShortcut<'delete'>;
    head: FexiosRequestShortcut<'head'>;
    options: FexiosRequestShortcut<'options'>;
    trace: FexiosRequestShortcut<'trace'>;
}
declare const createFexios: typeof Fexios.create;
declare const fexios: Fexios;

export { Fexios, FexiosError, FexiosErrorCodes, FexiosResponse, FexiosResponseError, createFexios, fexios as default, fexios, isFexiosError };
export type { FexiosConfigs, FexiosContext, FexiosFinalContext, FexiosHook, FexiosHookStore, FexiosHooksNameMap, FexiosInterceptor, FexiosInterceptors, FexiosLifecycleEvents, FexiosMethods, FexiosRequestOptions, FexiosRequestShortcut };
