{{> ../common}}

import querystring from "querystring";
// @ts-ignore
import Taro from "@tarojs/taro";

const TaroRequest = Taro.request;
type TaroRequestAPI = typeof Taro.request;
type TaroRequestInit = Omit<Taro.request.Option, "url" | "method">;
type TaroRequestHeader = TaroRequestInit["header"];
type TaroRequestData = TaroRequestInit["data"];
type TaroRequestMethod = keyof Taro.request.method;
type TaroRequestResponse = Taro.request.SuccessCallbackResult; 

export const DEFAULT_HEADERS: TaroRequestHeader = {};

export class BaseApi {
	public static beforeRequest?: (method: TaroRequestMethod, localVarPath: string, queryParameters: any, bodyDict: TaroRequestData) => void;
	public static afterResponse?: (response: TaroRequestResponse) => void;
	constructor(protected fetch: TaroRequestAPI = TaroRequest, protected basePath: string = BASE_PATH) {
	}
	/** Assert required */
	protected r = (params: any, fieldNames: string[]) => {
		for (const fieldName of fieldNames) {
			const value = params[fieldName];
			if (value === null || value === undefined) {
				throw new Error(`field: ${fieldName} required`);
			}
		}
	}
	protected ajax = async (method: TaroRequestMethod, localVarPath: string, queryParameters: any, bodyDict: TaroRequestData): Promise<any> => {
		const f = this.fetch;
		BaseApi.beforeRequest?.(method, localVarPath, queryParameters, bodyDict);
		const query = querystring.stringify(queryParameters);
		const pathAndQuery = query ? localVarPath + "?" + query : localVarPath;
		let fetchOptions: TaroRequestInit = {
			header: {
				"Content-Type": "application/json",
				...DEFAULT_HEADERS
			},
		};
		if (bodyDict) {
            fetchOptions.data = bodyDict;
        }
		const response = await f({
            url: this.basePath + pathAndQuery,
            method,
            ...fetchOptions,
        });
        BaseApi.afterResponse?.(response);
        if (response.statusCode >= 200 && response.statusCode < 300) {
            return response.data;
        } else {
            throw response.data;
        }
	}
}
