import moment = require("moment");
import { ERRORENUM } from "../config/errorEnum";
import { BizError } from "./bizError";
const md5 = require("md5");

/**
 * 生成任务id
 * @param uscc 企业标识
 * @returns 
 */
export function getTaskId(uscc:string) {
    return `${uscc}${getTimeKey()}`
}

/**
 * 获取当前日期的key
 * @returns 
 */
export function getTimeKey() {
    return `${new Date().getFullYear()}${new Date().getMonth() + 1 }`
}

/**
 * 通过config校验参数param
 * 包括类型 String, Number, Boolean, [Number]
 * @param name 被调用的方法名
 * @param config 校验配置
 * @param param 需要校验的参数
 */
export function checkParamater(name:string, keyTypeConf:object, param:object) {
    for (let key in keyTypeConf ) {
        if ( !param[key] ) throw new BizError(ERRORENUM.表单校验失败, name, `缺失${key}字段`);
        let type = typeof param[key];
        switch(keyTypeConf[key]) {
            case 'Number':
                if ( type != 'number' ) throw new BizError(ERRORENUM.表单校验失败, name, `${key}应是number型 而不是${type}`);
            break;
            case 'String':
                if ( type != 'string' ) throw new BizError(ERRORENUM.表单校验失败, name, `${key}应是string型 而不是${type}`);
            break;
            case 'Boolean':
                if ( type != 'boolean' ) throw new BizError(ERRORENUM.表单校验失败, name, `${key}应是boolean型 而不是${type}`); 
            break;
            case '[Number]':
                if ( !Array.isArray(param[key]) ) throw new BizError(ERRORENUM.表单校验失败, name, `${key}应是数组型 而不是${type}`);
                for (let i =0; i <  param[key].length; i++) {
                    let item = param[key][i];
                    if ( typeof item != 'number' ) {
                        throw new BizError(ERRORENUM.表单校验失败, name, `${key}应是number型数组其中下标${i}是${typeof item}`);
                    }
                }
            break;
            case '[Object]':
                if ( !Array.isArray(param[key]) ) throw new BizError(ERRORENUM.表单校验失败, name, `${key}应是数组型 而不是${type}`);
                for (let i =0; i <  param[key].length; i++) {
                    let item = param[key][i];
                    if ( typeof item != 'object' ) {
                        throw new BizError(ERRORENUM.表单校验失败, name, `${key}应是object型数组其中下标${i}是${typeof item}`);
                    }
                }
            break;
        }
    }
    for (let key in param) {
        if (!keyTypeConf[key]) throw new BizError(ERRORENUM.表单校验失败, name, `多余${key}字段`);
    }
    return true;
}

/**
 * 匹配新旧对象变化
 * 将newObj 与 oldObj 比对，将newObj中发生变化的key返回
 * 使用前需要校验对象中的内容
 * @param newObj 新对象
 * @param oldObj 旧对象
 * @returns [key] 发生变化的key
 */
export function checkChange(newObj, oldObj) {
    let changeKeyList = [];
    for (let newKey in newObj) {
        if (`${newObj[newKey]}` != `${oldObj[newKey]}`) changeKeyList.push(newKey);
    }
    return changeKeyList;
}

/**
 * 密码加密
 * @param uscc 信用代码
 * @param pwd 密码
 * @returns md5后的密码
 */
export function getPwdMd5(uscc:string, pwd:string) {
    return md5(uscc+pwd);
}


/**
 * 校验请求参数
 * 判断参数为必填
 * @param conf 
 * @param param 
 * @returns 
 */
export function checkReqParam(conf, param) {
    for (let key in conf ) {
        if ( typeof param[key] != 'boolean' && !param[key] ) throw new BizError(ERRORENUM.参数错误, `缺失${key}字段`);
        let type = typeof param[key];
        switch(conf[key]) {
            case 'Number':
                if ( type != 'number' ) throw new BizError(ERRORENUM.参数错误, `${key}应是number型 而不是${type}`);
            break;
            case 'String':
                if ( type != 'string' ) throw new BizError(ERRORENUM.参数错误, `${key}应是string型 而不是${type}`);
            break;
            case 'Boolean':
                if ( type != 'boolean' ) throw new BizError(ERRORENUM.参数错误, `${key}应是boolean型 而不是${type}`); 
            break;
            case '[Number]':
                if ( !Array.isArray(param[key]) ) throw new BizError(ERRORENUM.参数错误, `${key}应是数组型 而不是${type}`);
                for (let i =0; i <  param[key].length; i++) {
                    let item = param[key][i];
                    if ( typeof item != 'number' ) {
                        throw new BizError(ERRORENUM.参数错误, `${key}应是number型数组其中下标${i}是${typeof item}`);
                    }
                }
            break;
            case 'Object':
                if ( type != 'object' ) throw new BizError(ERRORENUM.参数错误, `${key}应是Object型 而不是${type}`);
                if ( Array.isArray(param[key]) ) throw new BizError(ERRORENUM.参数错误, `${key}应是Object型 而不是array`);
                try {
                    JSON.stringify(param[key]);
                } catch(err) {
                    throw new BizError(ERRORENUM.参数错误, `${key}应是Object型 转换JSON时失败`); 
                }
                
            break;
        }
    }
    for (let key in param) {
        if (!conf[key]) throw new BizError(ERRORENUM.表单校验失败, name, `多余${key}字段`);
    }
    return param;
}

/**
 * 校验请求参数
 * 判断参数可以不填
 * @param conf 
 * @param param 
 * @returns 
 */
export function checkParamaterType(conf, param) {
    for (let key in conf ) {
        if (!param[key]) continue;
        let type = typeof param[key];
        switch(conf[key]) {
            case 'Number':
                if ( type != 'number' ) throw new BizError(ERRORENUM.参数错误, `${key}应是number型 而不是${type}`);
            break;
            case 'String':
                if ( type != 'string' ) throw new BizError(ERRORENUM.参数错误, `${key}应是string型 而不是${type}`);
            break;
            case 'Boolean':
                if ( type != 'boolean' ) throw new BizError(ERRORENUM.参数错误, `${key}应是boolean型 而不是${type}`); 
            break;
            case '[Number]':
                if ( !Array.isArray(param[key]) ) throw new BizError(ERRORENUM.参数错误, `${key}应是数组型 而不是${type}`);
                for (let i =0; i <  param[key].length; i++) {
                    let item = param[key][i];
                    if ( typeof item != 'number' ) {
                        throw new BizError(ERRORENUM.参数错误, `${key}应是number型数组其中下标${i}是${typeof item}`);
                    }
                }
            break;
            case 'Object':
                if ( type != 'object' ) throw new BizError(ERRORENUM.参数错误, `${key}应是Object型 而不是${type}`);
                if ( Array.isArray(param[key]) ) throw new BizError(ERRORENUM.参数错误, `${key}应是Object型 而不是array`);
                try {
                    JSON.stringify(param[key]);
                } catch(err) {
                    throw new BizError(ERRORENUM.参数错误, `${key}应是Object型 转换JSON时失败`); 
                }
                
            break;
        }
    }
    for (let key in param) {
        if (!conf[key]) throw new BizError(ERRORENUM.表单校验失败, name, `多余${key}字段`);
    }
    return param;
}

/**
 * 获取token
 * @param uscc 统一信用代码
 */
export function getToken(uscc:string) {
    return md5(`${uscc}${new Date().valueOf()}${Math.ceil(Math.random() *100)}`);
}


/**
 * 根据conf截取data中的数据
 * @param conf 
 * @param data 
 * @returns 
 */
export function extractData(conf, data) {
    let result = {};
    for (let key in conf) {
        let confInfo = conf[key];
        if (confInfo.changeDate) {
            result[key] = moment(data[key]).format("YYYY-MM-DD");
        }else {
            result[key] = data[key];
        }
    }
    return result;
}


/**
 * 校验value是否符合传入的枚举
 * @param enumConf 目标枚举
 * @param value 目标值
 * @returns true/false 是否通过校验
 */
export function checkEnumValue(enumConf, value:any) {
    if ( typeof value == 'number' ) {
        return enumConf[value] ? true : false;
    }
    let checkSuccess = true;
    value.forEach(item => {
        if ( !enumConf[item] ) checkSuccess = false;
    });

    return checkSuccess;
}


/**
 * 将枚举值转换成对应的枚举名(key)
 * @param enumConf 目标枚举
 * @param value 目标值
 * @returns string  返回字符串 如果传入多个枚举值，就拼接字符串
 */
export function changeEnumValue(enumConf, value:any) {
    if ( typeof value == 'number' ) {
        return enumConf[value];
    }
    let str = "";
    value.forEach((item, index) => {
        str += enumConf[item];
        if (index == value.length-1) str+="";
        else str += ","
    });

    return str;
}
