import axios, { AxiosInstance, AxiosResponse, AxiosRequestConfig } from 'axios';
const querystring = require('querystring');
import * as FormData from 'form-data';
const crypto = require("crypto");
/**
 * 基于Axios框架实现的Http工具
 * @author wufl2019@qq.com
 * @date 2020-06-23
 */
export class HttpClient {

    private readonly axios: AxiosInstance;

    constructor(_timeout: number = 5000) {
        this.axios = axios.create({
            timeout: _timeout
        });
    }

    /**
     * @desc get请求
     * @param {String} path 请求api路径
     * @param {any} data 参数对象
     * @param {any} config 局部配置 {headers: {'X-Custom-Header': 'foobar'}}
     */
    async get(url: string, data: any = {}, config: any = {}): Promise<AxiosResponse> {
        return await this.axios.get(url, {
            params: data,
            ...config
        })
    }
    async getImg(url: string, data: any = {}, config: any = {}): Promise<AxiosResponse> {
        return await this.axios.get(url, {
            responseType: 'arraybuffer',
            params: data,
            ...config
        })
    }

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

    /**
     * @desc post 
     * @param {String} path 请求api路径
     * @param {any} data 参数对象
     * @param {any} config 局部配置 {headers: {'X-Custom-Header': 'foobar'}}
     */
    async post(url: string, data: any = {}, config: any = {}): Promise<AxiosResponse> {
        return await this.axios.post(url, data, config);
    }


    /**
     * @desc request 
     * @param {any} config AxiosRequestConfig
     */
    async request(config: AxiosRequestConfig = {}): Promise<AxiosResponse> {
        return await this.axios.request(config);
    }

    async  postJsonByDigest(requestUrl, bodyObj, username, passwd, config): Promise<any> {
        config = [];
        if (!config['headers']) {
            config['headers'] = {}
        }
        config['headers']['content-type'] = 'application/json;charset=utf-8';
        try {
            let x = await axios.post(requestUrl, bodyObj, config);
            return x;
        } catch (e) {
            if (e.response.status == 401) {
                var uri = requestUrl.split(/^https?:\/\/[^/]+/).filter(function (v) { return v !== ''; })[0];
                const authDetails = e.response.headers['www-authenticate'].split(', ').map(v => v.split('='));
                let count = 0;
                ++count;
                const nonceCount = ('00000000' + count).slice(-8);
                const cnonce = crypto.randomBytes(24).toString('hex');

                const realm = authDetails[0][1].split(',')[0].replace(/"/g, '');
                const nonce = authDetails[0][3].split(',')[0].replace(/"/g, '');

                const md5 = str => crypto.createHash('md5').update(str).digest('hex');

                const HA1 = md5(`${username}:${realm}:${passwd}`);
                const HA2 = md5(`POST:${uri}`);
                const response = md5(`${HA1}:${nonce}:${nonceCount}:${cnonce}:auth:${HA2}`);

                const authorization = `Digest username="${username}",realm="${realm}",` +
                    `nonce="${nonce}",uri="${uri}",qop="auth",algorithm="MD5",` +
                    `response="${response}",nc="${nonceCount}",cnonce="${cnonce}"`;
                config.headers = { 'Authorization': authorization };
                try {
                    let x22 = await axios.post(requestUrl, bodyObj, { headers: { authorization } });
                    return x22;
                } catch (ex2) {
                    return ex2;
                }
            }
        }

    }
}


export default new HttpClient();