import { logger } from "mslib"
import * as crypto from 'crypto'
import { v4 } from 'uuid'
import { AxiosInstance, AxiosResponse } from 'axios';

/**
 * 统一平台对接接口
 * @date 2021-01-07 08:08:08
 * @author 周勇强
 */
export class TyptApi {
    private appId: string;
    private appSecret: string;
    private url: string;
    private version: string;
    private axios: AxiosInstance;

    /**
     * 初始化统一平台参数
     */
    constructor(appId: string, appSecret: string, url: string, version: string) {
        this.appId = appId;
        this.appSecret = appSecret;
        this.url = url;
        this.version = version;
    }

    /**
     * 统一平台接口调用入口
     * @param uri           请求地址uri（除ip和端口）例：/api/wec/GetCarCardList
     * @param serviceCode   例：getCarCardList
     * @param params        请求参数(appId、key、serviceCode、ts、reqId不用传)
     */
    async call(uri: string, serviceCode: string, params): Promise<TyptApiOpResult> {
        try {
            let url = `${this.url}${uri}`;
            // params.serviceCode = serviceCode;
            // params = params || {};
            
            params.reqId = v4();
            params.ts = new Date().getTime();
            params.key = this.sign(params, this.appSecret);
            //appId不能参与加密
            params.appId =Number(this.appId) ;
            let headers = {};
            headers['kt-lotcodes'] = params && params['parkId'] ? params['parkId'] : "";
            headers['version'] = this.version
            let callObj = {
                url: url,
                key: params.key,
                ts: params.ts,
                data: params,
                headers: headers
            }
            logger.info(`\n调用统一平台接口，传入参数======>\n${JSON.stringify(callObj)}\n=======\n`);
            let result = await this.postJson(url, params, headers);
            logger.info(`\n调用统一平台接口，返回结果======>`
                + `\nstatus=${result.status}\nstatusText=${result.statusText}`
                + `\ndata=${JSON.stringify(result.data)}\n=======\n`);
            if (result.status != 200) {
                return TyptApiOpResult.opError(`调用统一平台接口，调用失败: ${result.statusText}`)
            }
            if (!result.data) {
                return TyptApiOpResult.opError(`调用统一平台接口返回数据为空!`)
            }
            if (result.data.resCode && result.data.resCode != "0" && result.data.resCode != 0 && result.data.resCode != "200") {
                return TyptApiOpResult.opError(result.data.resCode + "/" + result.data.resMsg)
            }
            if (result.data.respCode && result.data.respCode != "0" && result.data.respCode != 0 && result.data.respCode != "200") {
                return TyptApiOpResult.opError(result.data.respCode + "/" + result.data.respMsg)
            }
            return TyptApiOpResult.opSuccess("调用统一平台接口成功!", result.data.data instanceof Object ? result.data.data : JSON.parse(result.data.data))
        } catch (e) {
            return TyptApiOpResult.opError(e.toString());
        }
    }

    /**
     * 对数据进行签名
     */
    private sign(data, secret) {
        logger.info(`统一平台接口签名，传入的数据字段\n=======sign-data=======\n${JSON.stringify(data)}\n====================\n`);
        let result = ``;
        let keys = [];
        for (var k in data) {
            if (k == 'sign') {
                continue;
            }
            keys.push(k);
        }
        keys.sort();
        for (let i = 0; i < keys.length; i++) {
            let key = keys[i];
            let valueObj = data[key];
            if (valueObj instanceof Array || valueObj instanceof Object) {
                //忽略复杂对象
                logger.info("统一平台接口签名，当前key为复杂对象，不能够参与加密。。。key:%s,valueObj:%s", key, valueObj);
            } else {
                let valueStr = valueObj;
                result = `${result}${key}=${valueStr}&`;
            }
        }
        result = `${result}${secret}`;
        logger.info(`统一平台接口签名源字段：\n=======sign-src=======\n${result}\n=====================\n`);
        return this.md5(result);
    }

    /**
     * md5加密并转大写
     */
    private md5(txt: string): string {
        const hash = crypto.createHash('md5');
        hash.update(txt);
        return hash.digest('hex').toUpperCase()
    }

    /**
     * http请求统一平台，设置headers
     */
    private async postJson(url: string, bodyObj: object = {}, headers: object = {}): Promise<AxiosResponse> {
        let config = {}, requestUrl = url
        config['headers'] = headers;
        config['headers']['content-type'] = 'application/json;charset=utf-8';
        logger.info("最终请求：requestUrl:【%s】,bodyObj:【%s】,config:【%s】",requestUrl,JSON.stringify(bodyObj),JSON.stringify(config));
        const response: AxiosResponse = await this.axios.post(requestUrl, bodyObj, config);
        logger.info("最终返回："+JSON.stringify(response.data));
        return response
    }
}

export class TyptApiOpResult {
    code: number
    message: string
    msg: string
    data: any

    success(): boolean {
        return this.code == 2000
    }

    static opSuccess(message, data?: any): TyptApiOpResult {
        let result = new TyptApiOpResult()
        result.code = 2000
        result.message = message
        result.data = data
        return result
    }

    static opError(message: string): TyptApiOpResult {
        let result = new TyptApiOpResult()
        result.code = 5000
        result.message = message
        return result
    }
}