const fs = require('fs');
const objsettings = require('../config/objsettings');
const settings = require('../config/settings');
const request = require('request');
const cryptoJS = require('crypto-js');
const md5 = require('MD5');

class System {
  static declare(ns) {
    const ar = ns.split('.');
    let root = System;
    for (let i = 0, len = ar.length; i < len; ++i) {
      const n = ar[i];
      if (!root[n]) {
        root[n] = {};
        root = root[n];
      } else {
        root = root[n];
      }
    }
  }
  static async delReq(url, qdata) {
    const rtn = {};
    const promise = new Promise(((resv, rej) => {
      request.del({
        url,
        qs: qdata,
      }, (error, response, body) => {
        rtn.statusCode = response.statusCode;
        if (!error) {
          if (body) {
            const data = JSON.parse(body);
            rtn.data = data;
          } else {
            rtn.data = null;
          }
          resv(rtn);
        } else {
          rej(error);
        }
      });
    }));
    return promise;
  }
  static async getReq(url, qdata) {
    const rtn = {};
    const promise = new Promise(((resv, rej) => {
      request.get({
        url,
        json: true,
        qs: qdata,
      }, (error, response, body) => {
        rtn.statusCode = response.statusCode;
        if (!error) {
          if (body) {
            rtn.data = body;
          } else {
            rtn.data = null;
          }
          resv(rtn);
        } else {
          rej(error);
        }
      });
    }));
    return promise;
  }
  static async postJsonTypeReq(url, data, md = 'POST') {
    const rtn = {};
    const promise = new Promise(((resv, rej) => {
      request({
        url,
        method: md,
        json: true,
        headers: {
          'content-type': 'application/json',
        },
        body: data,
      }, (error, response, body) => {
        console.log(error);
        if (!error) {
          rtn.statusCode = response.statusCode;
          if (body) {
            rtn.data = body;
          } else {
            rtn.data = null;
          }
          resv(rtn);
        } else {
          rej(error);
        }
      });
    }));
    return promise;
  }
  static async post3wFormTypeReq(url, data) {
    const rtn = {};
    const promise = new Promise(((resv, rej) => {
      request.post({
        url,
        form: data,
      }, (error, response, body) => {
        rtn.statusCode = response.statusCode;
        if (!error) {
          const data = JSON.parse(body);
          rtn.data = data;
          resv(rtn);
        } else {
          rej(error);
        }
      });
    }));
    return promise;
  }
  static async postMpFormTypeReq(url, formdata) {
    const promise = new Promise(((resv, rej) => {
      request.post({
        url,
        formData: formdata,
      }, (error, response, body) => {
        if (!error && response.statusCode == 200) {
          resv(body);
        } else {
          rej(error);
        }
      });
    }));
    return promise;
  }

  /**
	 * 请求返回成功
	 * @param {*} data 操作成功返回的数据,有值为成功，无值为失败
	 * @param {*} okmsg 操作成功的描述
	 * @param {*} req 请求头信息
	 */
  static getResult(data, opmsg = '操作成功', req) {
    return {
      status: !data ? -1 : 0,
      msg: opmsg,
      data,
      bizmsg: req && req.session && req.session.bizmsg ? req.session.bizmsg : 'empty',
    };
  }
  /**
	 * 请求返回成功
	 * @param {*} data 操作成功返回的数据
	 * @param {*} okmsg 操作成功的描述
	 */
  static getResultSuccess(data, okmsg = 'success') {
    return {
      status: 0,
      msg: okmsg,
      data,
    };
  }
  /**
	 * 请求返回失败
	 * @param {*} status 操作失败状态，默认为-1
	 * @param {*} errmsg 操作失败的描述，默认为fail
	 * @param {*} data 操作失败返回的数据
	 */
  static getResultFail(status = -1, errmsg = 'fail', data = null) {
    return {
      status,
      msg: errmsg,
      data,
    };
  }
  /**
	 * 请求处理异常
	 * @param {*} errmsg 操作失败的描述，默认为fail
	 * @param {*} data 操作失败返回的数据
	 */
  static getResultError(errmsg = 'fail', data = null) {
    return {
      status: -200,
      msg: errmsg,
      data,
    };
  }
  static register(key, ClassObj, groupName, filename) {
    if (System.objTable[key] != null) {
      throw new Error('相同key的对象已经存在');
    } else {
      let obj;
      if (ClassObj.name === 'ServiceBase') {
        obj = new ClassObj(groupName, filename.replace('Sve', 'Dao'));
      } else {
        obj = new ClassObj(groupName, filename);
      }
      System.objTable[key] = obj;
    }

    return System.objTable[key];
  }
  static getObject(objpath) {
    const pathArray = objpath.split('.');
    const packageName = pathArray[0];
    const groupName = pathArray[1];
    let filename = pathArray[2];
    let classpath = '';
    if (filename) {
      classpath = `${objsettings[packageName]}/${groupName}`;
    } else {
      classpath = objsettings[packageName];
      filename = groupName;
    }

    const objabspath = `${classpath}/${filename}.js`;

    // 判断文件的存在性
    // 如果不存在，需要查看packageName
    // 如果packageName=web.service,dao

    if (System.objTable[objabspath] != null) {
      return System.objTable[objabspath];
    }
    let ClassObj = null;
    try {
      ClassObj = require(objabspath);
    } catch (e) {
      console.log('eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee');
      console.log(e);
      const fname = objsettings[`${packageName}base`];
      ClassObj = require(fname);
    }
    if (ClassObj.name == 'Dao') {
      const modelname = filename.substring(0, filename.lastIndexOf('Dao'));
      return System.register(objabspath, ClassObj, modelname);
    }
    if (ClassObj.name.indexOf('Ctl') >= 0) {
      console.log(ClassObj.name);
    }
    return System.register(objabspath, ClassObj, groupName, filename);
  }

  static getSysConfig() {
    const configPath = `${settings.basepath}/app/base/db/metadata/index.js`;
    // if(settings.env=="dev"){
    // 	console.log("delete "+configPath+"cache config");
    // 	delete require.cache[configPath];
    // }
    delete require.cache[configPath];
    const configValue = require(configPath);
    return configValue.config;
  }
  static getClientIp(req) {
    const ip = req.headers['x-forwarded-for']
			|| req.ip
			|| req.connection.remoteAddress
			|| req.socket.remoteAddress
			|| (req.connection.socket && req.connection.socket.remoteAddress) || '';
    const x = ip.match(/(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])$/);
    if (x) {
      return x[0];
    }
    return 'localhost';
  };

  /**
	* 记录日志信息
	* @param {*} opTitle 操作的标题
	* @param {*} params 参数
	* @param {*} identifyCode 业务标识
	* @param {*} resultInfo 返回结果
	* @param {*} errorInfo 错误信息
	*/
  static execLogs(opTitle, params, identifyCode, resultInfo, errorInfo) {
    const reqUrl = settings.logUrl();
    let isLogData = true;
    if (params.method && (params.method.indexOf('find') >= 0 || params.method.indexOf('get') >= 0)) {
      isLogData = false;
    }
    const param = {
      actionType: 'produceLogsData', // Y 功能名称
      actionBody: {
        opTitle: opTitle || '', // N 操作的业务标题
        identifyCode: identifyCode || 'brg-center-manage', // Y 操作的业务标识
        indexName: settings.logindex, // Y es索引值，同一个项目用一个值
        messageBody: params, // 日志的描述信息
        resultInfo: isLogData ? resultInfo : { status: resultInfo.status }, // 返回信息
        errorInfo, // 错误信息
        requestId: resultInfo.requestId || '',
      },
    };
    console.log('写入日志内容:');
    console.log(JSON.stringify(param));
    const P = new Promise((resv, rej) => {
      this.postJsonTypeReq(reqUrl, param).then((res) => {
        if (res.statusCode == 200) {
          resv(res.data);
        } else {
          rej(null);
        }
      });
    });
    return P;
  }

  /**
  * 加密信息
  * @param {*} opStr
  */
  static encryptStr(opStr) {
    if (!opStr) {
      return 'opStr is empty';
    }
    const keyHex = cryptoJS.enc.Utf8.parse(settings.encrypt_key);
    const ivHex = cryptoJS.enc.Utf8.parse(settings.encrypt_secret.substring(0, 8));
    const cipherStr = cryptoJS.TripleDES.encrypt(opStr, keyHex, { iv: ivHex }).toString();
    return cipherStr;
  }
  /**
	 * 解密信息
	 * @param {*} opStr
	 */
  static decryptStr(opStr) {
    if (!opStr) {
      return 'opStr is empty';
    }
    const keyHex = cryptoJS.enc.Utf8.parse(settings.encrypt_key);
    const ivHex = cryptoJS.enc.Utf8.parse(settings.encrypt_secret.substring(0, 8));
    const bytes = cryptoJS.TripleDES.decrypt(opStr, keyHex, {
      iv: ivHex,
    });
    const plaintext = bytes.toString(cryptoJS.enc.Utf8);
    return plaintext;
  }

  /**
	 * 签名认证
	 * @param {json} vo json对象
	 * @param {string} secret 签名信息
	 */
  static signValid(obj, secret) {
    console.log('secret:{}', secret);
    // obj json字符串
    let svrSign;
    if (obj == '{}' || !secret || secret == 'undefined') {
      svrSign = '';
    } else {
      // 对传入的json   obj进行处理得到toSignStr
      const arr = [];
      for (const key in obj) {
        arr.push(key);
      }
      arr.sort();
      let str = '';
      for (const i in arr) {
        if (arr[i] != 'sign' && arr[i] != 'ip'
					&& (!(Object.prototype.toString.call(obj[arr[i]]) == '[object Object]')// || Object.prototype.toString.call(obj[arr[i]]) == '[object Array]'
						&& ((obj[arr[i]] || obj[arr[i]] === 0 || obj[arr[i]] === false) && obj[arr[i]] != 'undefined'))) {
          str += `${arr[i]}=${obj[arr[i]]}&`;
        }
      }
      const toSignStr = str.substr(0, str.length - 1);
      const sb = toSignStr + secret;
      console.log(`cmd=ApiSignUtils:toSign msg=original Sign:${sb.toString()}`);
      // 对sb进行md5加密后得到svrSign
      svrSign = md5(sb);
      console.log(`svrSign===>${svrSign}`);
    }
    return svrSign;
  }
  /**
	 * 队列操作
	 * @param {json}
			pushUrl	string	推送URL地址
		actionType	string	推送地址接收时的功能名称
		notifyUrl	string	推送成功后通知的Url
		messageBody	json	推送的业务消息，必须有一项对象属性值
		headData	json	请求头信息
		requestId	string	请求id
	 */
  static async queueOper(obj) {
    if (obj.pushUrl && obj.actionType && obj.messageBody) {
      try {
        const rc = this.getObject('util.execClient');
        const reqUrl = settings.queueUrl;
        const param = {
          actionType: 'produceData',
          actionBody: {
            pushUrl: obj.pushUrl,
            actionType: obj.actionType,
            identifyCode: 'book-manage',
            messageBody: obj.messageBody,
            isMessageBody: 1, // 对融易算只发送放messageBody
          },
        };
        if (obj.notifyUrl) {
          param.actionBody.notifyUrl = obj.notifyUrl;
        }
        if (obj.headData) {
          param.actionBody.headData = obj.headData;
        }
        if (obj.requestId) {
          param.requestId = obj.requestId;
        }

        const result = await rc.execPost(param, reqUrl);
        const j = JSON.parse(result.stdout);
        if (j.status == 1) {
          return this.getResult(j);
        }

        return this.getResultError('队列返回失败');
      } catch (error) {
        return this.getResultError(error);
      }
    } else {
      return this.getResultError('参数错误');
    }
  }
}
Date.prototype.Format = function (fmt) { // author: meizz
  const o = {
    'M+': this.getMonth() + 1,                 // 月份
    'd+': this.getDate(),                    // 日
    'h+': this.getHours(),                   // 小时
    'm+': this.getMinutes(),                 // 分
    's+': this.getSeconds(),                 // 秒
    'q+': Math.floor((this.getMonth() + 3) / 3), // 季度
    S: this.getMilliseconds(),             // 毫秒
  };
  if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (`${this.getFullYear()}`).substr(4 - RegExp.$1.length));
  for (const k in o) if (new RegExp(`(${k})`).test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : ((`00${o[k]}`).substr((`${o[k]}`).length)));
  return fmt;
};


/**
 * 常用 ENUM
 */

// 表分类
System.FLOWCODE = {
  BIZ: 'BIZ', // 商机表
  SCHEME: 'SCHEME', // 方案表
  DELIVERY: 'DELIVERY', // 服务单表
};
// 服务名称c
System.SERVICECODE = {
  FT: 'bookkeeping',  // 财税项目
};

// 资质服务单状态
System.SERVERSESTATUS = {
  RECEIVED: 'received', // 已接单
  WAITUSERCONFIRM: 'waituserconfirm', // 待用户确认
  INSERVICE: 'inservice', // 服务中
  CLOSED: 'closed', // 已关闭 、已终止
  SUCCESS: 'success', // 服务已完成
  NOTSETUP: 'notsetup', // 未建账
  SETUP: 'setup', // 建账
};

/*
编码说明，
1000----1999  为请求参数验证和app权限验证
2000----2100  为请求用户信息操作验证，如：注册，登录，获取验证码，修改用户信息，修改用户密码
 */


System.objTable = {};
// 访问token失效，请重新获取
System.tokenFail = 1000;
// appKey授权有误
System.appKeyError = 1100;
// 应用处于待审核等待启用状态
System.waitAuditApp = 1110;
// 获取访问token失败
System.getAppInfoFail = 1130;

// 已经存在此用户，注册失败
System.existUserRegFail = 2000;
// 用户名或密码错误
System.userLoginFail = 2010;
// 用户名错误
System.userNameLoginFail = 2020;
// 验证验证码错误
System.verifyVCodeFail = 2030;
// opencode存储的值已经失效
System.verifyOpencodeFail = 2040;

// 重复操作
System.redoFail = 2050;
module.exports = System;

// (async ()=>{
// 	try{
// 		let d=await System.getReq("http://127.0.0.1:8001x/services")
// 		console.log(d)
// 	}catch(e){
//         console.log(e);
// 	}
// })()

// (async () => {
// 	var obj = {
// 		"postWay": '2',
// 		"courier_number": '1805679087555',
// 		"companyId": 102,
// 		"customerId": 499482,
// 		"sign": '57acb7037f64d558edf2e844340791e2',
// 		"currentPeriod": 202001
// 	}
// 	var secret = "2a24a72dc78679bb0796dd3af50a429a";
// 	try {
// 		var flag = await System.signValid(obj, secret)
// 		console.log(flag);
// 	} catch (e) {
// 		console.log(e);
// 	}
// })()
