import axios, {AxiosInstance} from 'axios';
import {IHttpResponse} from "./IHttpResponse";
import {MsFile} from "../../model/MsFile";
import {RequestBodyType} from "../../enums/RequestBodyType";
import {HttpMethodType} from "../../enums/HttpMethodType";
import {ServiceClientConfig} from "../../config/ServiceClientConfig";
import * as FormData from "form-data";


const querystring = require('querystring');


export class SimpleHttpUtil {

    private readonly axios: AxiosInstance;
    private readonly serviceClientConfig: ServiceClientConfig;

    constructor(serviceClientConfig: ServiceClientConfig) {
        this.serviceClientConfig = serviceClientConfig;
        this.axios = axios.create({
            timeout: serviceClientConfig.requestTimeout || 8000
        });
        serviceClientConfig.configAxiosInterceptors(this.axios.interceptors.request, this.axios.interceptors.response)
    }

    /**
     * @desc get请求
     * @param {String} path 请求api路径
     * @param {Object} data 参数对象
     * @param {Object} config 局部配置 {headers: {'X-Custom-Header': 'foobar'}}
     */
    async get(url: string, data: object = {}, headers: object = {}): Promise<IHttpResponse> {
        let config = {}
        config['headers'] = headers
        const response: IHttpResponse = await this.axios.get(url, {
            params: data,
            ...config
        })
        return response
    }

    /**
     * @desc post表单请求
     * @param {String} path 请求api路径
     * @param {Object} data 参数对象
     * @param {Object} config 局部配置 {headers: {'X-Custom-Header': 'foobar'}}
     */
    async postForm(url: string, data: object = {}, headers: object = {}): Promise<IHttpResponse> {
        let config = {}
        config['headers'] = headers;
        config['headers']['content-type'] = 'application/x-www-form-urlencoded;charset=utf-8';
        const response: IHttpResponse = await this.axios.post(url, querystring.encode(data), config);
        return response
    }

    /**
     * @desc post表单请求
     * @param {String} path 请求api路径
     * @param {Object} data 参数对象
     * @param {Object} config 局部配置 {headers: {'X-Custom-Header': 'foobar'}}
     */
    async postJson(url: string, params: object = {}, bodyObj: object = {}, headers: object = {}): Promise<IHttpResponse> {
        let config = {}, requestUrl = url
        config['headers'] = headers;
        config['headers']['content-type'] = 'application/json;charset=utf-8';
        if (params && Object.keys(params).length) {
            requestUrl = requestUrl + '?' + querystring.encode(params)
        }
        const response: IHttpResponse = await this.axios.post(requestUrl, bodyObj, config);
        return response
    }

    async call(method: HttpMethodType, url: string, params: {}, bodyObj: object, headers: {}, bodyType: RequestBodyType): Promise<IHttpResponse> {
        let config = {}, requestBody = bodyObj || {}
        config['url'] = url;
        config['headers'] = headers;
        config['headers']['content-type'] = 'application/x-www-form-urlencoded;charset=utf-8';
        if (bodyType == RequestBodyType.RAW_JSON) {
            config['headers']['content-type'] = 'application/json;charset=utf-8';
        }
        config["method"] = method.toLowerCase();
        config["params"] = params;
        config["data"] = requestBody;

        const response: IHttpResponse = await this.axios.request(config);
        return response
    }


    /**
     * 文件上传
     * @param url
     * @param files
     * @param headers
     * @param config
     */
    async uploadFiles(url: string, data: object = {}, files: Array<MsFile>, headers: object = {}) {
        let formData = new FormData();
        files.forEach(file => {
            formData.append(file.name, file.readStream)
        })
        for (let attr in data) {
            formData.append(attr, data[attr])
        }
        let config = {}
        config['headers'] = headers;
        config['headers']['content-type'] = formData.getHeaders()['content-type'];

        const response: IHttpResponse = await this.axios.post(url, formData, config);
        return response
    }
}