import { OpenAPIV3 } from 'openapi-types';

declare const utils: {
    /**
     * 路由拼接查询字符串
     */
    uriConcatQuery(uri: string, query: Record<string, any> | undefined): string;
    formatBody(contentType: string, body: object | undefined, formData?: FormData): object | FormData | undefined;
};

declare const methods: readonly ["get", "post", "put", "patch", "delete"];
type Methods = (typeof methods)[number];
interface OpenapiClientAdapter<T extends object = object> {
    request(opts: {
        /**
         * 路由
         */
        uri: string;
        /**
         * 请求方法
         */
        method: Methods;
        /**
         * 路径参数
         */
        params?: Record<string, any>;
        /**
         * 查询字符串
         */
        query?: Record<string, any>;
        /**
         * 请求实体
         */
        body?: Record<string, any>;
        /**
         * 超时时间。单位：`ms`
         */
        timeout?: number;
        /**
         * 携带cookie
         */
        credentials?: boolean | 'same-origin' | 'include' | 'omit';
        /**
         * 请求实体类型
         */
        requestBodyType: 'multipart/form-data' | 'application/json' | (string & {});
        /**
         * 响应类型
         */
        responseType: 'json' | 'text';
        /**
         * 请求报文
         */
        headers: Record<string, any>;
        /**
         * 请求之前动态修改配置
         */
        onBeforeRequest?: (options: T) => T | void;
    }, helper: typeof utils): Promise<any>;
}

declare namespace string {
    /**
     * '12345'
     */
    type Number = string;
    type BigInt = string;
    /**
     * 2020-02-12T07:20:50.52Z
     */
    type DateTime = string;
    /**
     * 2020-02-12
     */
    type Date = string;
    /**
     * 07:20:50.52Z
     */
    type Time = string;
    /**
     * example@gmail.com
     */
    type Email = string;
    /**
     * https://example.com/foo/bar
     */
    type Uri = string;
    /**
     * 127.0.0.1
     */
    type IPv4 = string;
    /**
     * 2001:0DB8:0000:0023:0008:0800:200C:417A
     */
    type IPv6 = string;
}
declare namespace BaseOpenapiClient {
    interface UserInputOpts<T extends object = object> {
        headers?: Record<string, unknown>;
        /**
         * 超时时间。单位：`ms`
         */
        timeout?: number;
        /**
         * 携带cookie
         */
        credentials?: boolean | 'same-origin' | 'include' | 'omit';
        /**
         * 请求实体类型
         */
        requestBodyType?: 'multipart/form-data' | 'application/json' | (string & {});
        /**
         * 响应类型
         */
        responseType?: 'json' | 'text';
        /**
         * 请求之前动态修改配置
         */
        onBeforeRequest?: (options: T) => T | void;
    }
    interface FullOpts<T extends object = object> extends UserInputOpts<T> {
        params?: Record<string, any>;
        query?: Record<string, any>;
        body?: Record<string, any> | FormData;
    }
    type Prettify<T> = {
        [K in keyof T]: T[K] extends object ? Prettify<T[K]> : T[K];
    } & {};
}
declare abstract class BaseOpenapiClient<T extends object = object> {
    private readonly adapter;
    constructor(adapter: OpenapiClientAdapter<T>);
    protected replaceURI(uri: string, params?: Record<string, any>): string;
    protected request(uri: string, method: Methods, opts?: BaseOpenapiClient.FullOpts<T>): Promise<any>;
    protected pickContentTypes(_uri: string, _method: string): [
        BaseOpenapiClient.UserInputOpts['requestBodyType'],
        BaseOpenapiClient.UserInputOpts['responseType']
    ];
}

interface OpenapiClientConfig {
    /**
     * openapi本地或者远程文件，支持格式：`yaml | json`
     */
    url: string;
    /**
     * 过滤指定路由前缀的接口
     */
    includeUriPrefix?: string | RegExp | (string | RegExp)[];
    /**
     * 过滤指定标签
     */
    includeTag?: string | string[];
    /**
     * 路径参数替换规则。默认：`{*}`
     *
     * - /users/{id}
     * - /users/{id}/posts
     */
    paramsFormat?: string;
    /**
     * 项目名称，提供多个openapi路径时必须填写。
     * 比如项目名为`demo`，则导出的类为`OpenapiClientDemo`
     */
    projectName?: string;
    /**
     * 类的生成方式。默认值：`rest`
     * - `rest`       仅生成 **get|post|put|patch|delete** 几个固定方法，uri作为第一个参数传入。
     * - `rpc`        把 method+uri 拼接成一个方法。
     * - `rpc-group`  在rpc模式的基础上，根据tags把方法归类到不同的分组中。如果没有提供tags，则默认合并到`default`分组
     *
     * ```typescript
     * const client = new OpenapiClient();
     *
     * // rest模式
     * await client.get('/users/{id}', opts);
     * // rpc模式
     * await client.getUsersById(opts);
     * // rpc-group模式
     * await client.user.getUsersById(opts);
     * ```
     */
    classMode?: 'rest' | 'rpc' | 'rpc-group';
    /**
     * 指定在rpc(-group)模式下方法名的生成规则。默认：`method+uri`
     *
     * 假设有这么一段openapi文档：
     * ```json
     * {
     *   "paths": {
     *     "/some/client/users": {
     *       "get": {
     *         "operationId": "List_users",
     *         "parameters": [],
     *         "summary": "Users"
     *       }
     *     }
     *   }
     * }
     * ```
     * 1. 如果以 `method+uri` 的形式生成，则效果为：`openapi.getSomeClientUsers()`
     * 2. 如果以 `operationId` 的形式生成，则效果为：`openapi.listUsers()`
     *
     * 注意：如果operationId字段不存在，则仍以`method+uri`的规则生成
     */
    rpcName?: 'method+uri' | 'operationId';
    /**
     * 加载完openapi文档后的事件，允许直接对文档进行修改
     */
    onDocumentLoaded?: (doc: OpenAPIV3.Document) => OpenAPIV3.Document | void;
    /**
     * 输出文件路径。
     *
     * - 如果没有配置项目名，默认值：`./src/openapi/openapi.ts`
     * - 如果配置了项目名，默认值：`./src/openapi/${projectName}.ts`
     */
    outputFile?: string;
    /**
     * 开启后，`query`和`params`对象的属性类型中，`number`会被解析为`number | string`。默认值：`false`
     *
     * 不管是否开启都不会对请求造成影响，因为最终都会拼接到请求链接上变成一段完整的uri。
     *
     * ```typescript
     * // http://host:port/users/1?tag=234
     * openapi.getUsersById({ params: { id: 1 }, query: { tag: 234 } });
     * openapi.getUsersById({ params: { id: '1' }, query: { tag: '234' } });
     * ```
     */
    looseInputNumber?: boolean;
}
type DefineConfigOptions = OpenapiClientConfig | OpenapiClientConfig[] | ((env: string) => OpenapiClientConfig | OpenapiClientConfig[] | Promise<OpenapiClientConfig | OpenapiClientConfig[]>);
declare const defineConfig: (options: DefineConfigOptions) => DefineConfigOptions;

export { BaseOpenapiClient, type DefineConfigOptions, type Methods, type OpenapiClientAdapter, type OpenapiClientConfig, defineConfig, methods, string };
