const system = require("../../system");
const settings = require("../../../config/settings");
const md5 = require("md5");
const moment = require("moment");
const axios = require("axios");
const uuidv1 = require('uuid/v1');
class BpoSDPJApi {
  constructor() {

    this.cwxsignapiSve = system.getObject("service.cwxsignapiSve");
    this.redisClient = system.getObject("util.redisClient");

    this.cwxsigninfoSve = system.getObject("service.cwxsigninfoSve");

    this.utilesignbaoSve = system.getObject("service.utilesignbaoSve");

    this.ecompanySve = system.getObject("service.ecompanySve");
    this.etemplateSve = system.getObject("service.etemplateSve");
    this.econtractSve = system.getObject("service.econtractSve");

    this.dkcompanySve = system.getObject("service.dkcompanySve");
    this.dktemplateSve = system.getObject("service.dktemplateSve");
    this.dkcontractSve = system.getObject("service.dkcontractSve");

    this.EXCEPT_KEYS = ['sign'];

    this.ccashinfoSve =  system.getObject("service.ccashinfoSve");
    this.ecompanybusiDao =  system.getObject("db.ecompanybusiDao");
    this.qrClient = system.getObject("util.qrClient");
    this.idcardClient = system.getObject("util.idcardClient");
    this.esettleSve = system.getObject("service.esettleSve");

    this.ecompanybusiSve = system.getObject("service.ecompanybusiSve");

    this.tdevApi = require("./tdevApi");
    this.redisLock = system.getObject("util.redisLock");
    this.bankthreelogSve = system.getObject("service.bankthreelogSve");
    this.resultMap = {
      0:"操作成功",
      1:"操作失败",
      1001001:"签名失败",
      1002001:"参数错误",
      500:"接口异常",
    }
  }
  trim(o) {
    if(!o) {
      return "";
    }
    return o.toString().trim();
  }

  /**
   * 生成二维码
   * @param obj
   * @param req
   * @returns {Promise<{msg: string, code: number}>}
   */
  async cashQRCode(obj, req) {
    // 检验所有参数是否完整 如果出现非法参数直接返回
    if (!obj.appId) {
      return this.getBaseResult(1002001,"appId不存在");
    }
    if (!obj.mchtId) {
      return this.getBaseResult(1002001,"mchtId不存在");
    }
    if (!obj.outTradeNo) {
      return this.getBaseResult(1002001,"商户订单号[outTradeNo]不存在");
    }
    if (!obj.notifyUrl) {
      return this.getBaseResult(1002001,"商户订单号[notifyUrl]不存在");
    }
    let otnLen = this.trim(obj.outTradeNo).length;
    if (otnLen < 10 || otnLen > 32) {
      return this.getBaseResult(1002001,"商户订单号[outTradeNo]长度10-32");
    }

    if (!obj.amt) {
      return this.getBaseResult(1002001,"请设置申请金额");
    }
    if (!obj.ecid) {
      return this.getBaseResult(1002001,"ecid不存在");
    }

    // 获取api信息
    let api = await this.ecompanybusiSve.findOne({
      appId: obj.appId,
      etemplate_id: obj.ecid,
      mchtId: obj.mchtId,
    });
    if (!api) {
      return this.getBaseResult(1001003, "配置信息错误，请联系薪必果人员进行配置");
    }

    // 签名验证
    let param = {
      appId: obj.appId,
      ecid: obj.ecid,
      mchtId: obj.mchtId,
      amt: obj.amt,
      idName: obj.idName,
      idNo: obj.idNo,
      outTradeNo: obj.outTradeNo,
      nonceStr: obj.nonceStr,
      notifyUrl: obj.notifyUrl,
    };
    let sign = system.getSign(param, api.key, this.EXCEPT_KEYS);
    if (sign != obj.sign) {
      return this.getBaseResult(1001001, "签名失败");
    }

    try {
      // mchtId & ecid 进行联合查询 如果存在直接返回
      let _cCashInfo = await this.ccashinfoSve.findOne({
        app_id: obj.appId,
        mchtId: obj.mchtId,
        outTradeNo: obj.outTradeNo,
      }) || {};

      console.log(`bpoSDPJApi.js -> cashQRCode -> mchtId & ecid 进行联合查询 :参数=` + JSON.stringify(obj) + "  _cCashInfo = " + JSON.stringify(_cCashInfo));
      //如果二维码有效直接返回
      if( _cCashInfo.qrcode_status &&  _cCashInfo.qrcode){
        return this.getCodeResult(0,{"qrcode": _cCashInfo.qrcode});
      }

      if (!_cCashInfo.id) {
        _cCashInfo.app_type = api.app_type;
        _cCashInfo.outTradeNo = obj.outTradeNo;
        _cCashInfo.mchtId = obj.mchtId;
        _cCashInfo.ecid = api.etemplate_id;
        _cCashInfo.app_id = obj.appId;
        _cCashInfo.amt = Number(obj.amt || 0);
        _cCashInfo.idName = this.trim(obj.idName) || "";
        _cCashInfo.idNo = this.trim(obj.idNo) || "" ;
        _cCashInfo.notify_url = this.trim(obj.notifyUrl) || "";
        // 保存签约数据
        _cCashInfo = await this.ccashinfoSve.create(_cCashInfo);
      }

      // 拼接h5 http连接 http//xxx?mchtId=xxx&ecid=xxx&no=id
      let _no = await this.setNo(_cCashInfo.id.toString());
      _no = encodeURIComponent(_no);
      let custormUrl = `https://bpohhr.gongsibao.com/sdpj?no=${_no}&outTradeNo=${_cCashInfo.outTradeNo}&mchtId=${_cCashInfo.mchtId}`;
      // 生成二维码
      let url =await this.qrClient.generateQR(custormUrl);
      _cCashInfo.qrcode = url;
      _cCashInfo.qrcode_status = url ? 1 : 2;
      _cCashInfo.sign_url = custormUrl;
      _cCashInfo.save();
      return this.getCodeResult(0,{"qrcode": url || ""});
    } catch (e) {
      let result = {
        code: 500,
        msg: "接口异常"
      };
      console.log(e.stack);
      return result;
    }
  }

  setNo(no){
    return system.encryption(no);
  }

  async setNoTest(params){
    return system.encryption(params.no);
  }

  getNo(no) {
    return system.decryption(no);
  }

  /**
   * 二维码作废
   * @param obj
   * @param req
   * @returns {Promise<{msg: string, code: number, data: {}}>}
   */
  async removeQRCode(obj, req) {
    try {
      let params = {
        appId: obj.appId,
        mchtId: obj.mchtId,
        ecid: obj.ecid,
        outTradeNo: obj.outTradeNo,
        nonceStr: obj.nonceStr,
        sign: obj.sign,
      };

      let api = await this.ecompanybusiSve.findOne({
        appId: obj.appId,
        etemplate_id: obj.ecid,
        mchtId: obj.mchtId,
      });
      if (!api) {
        return this.getBaseResult(1001003, "配置信息错误，请联系薪必果人员进行配置");
      }

      let sign = system.getSign(params, api.key, this.EXCEPT_KEYS);
      if (obj.sign != sign) {
        return this.getBaseResult(1001001, "签名失败");
      }

      let cashInfo = await this.ccashinfoSve.findOne({
        mchtId: params.mchtId,
        outTradeNo: params.outTradeNo,
      });

      if (!cashInfo) {
        return this.getErrResult("二维码不存在");
      }
      if (cashInfo.trade_status) {
        return this.getErrResult("已经发起提现，不可作废");
      }
      if (cashInfo.qrcode_status != 2) {
        cashInfo.qrcode_status = 2;
        await cashInfo.save();
      }
    } catch (e) {
      console.log(e);
      return this.getErrResult("接口异常");
    }
    return this.getSuccessResult();
  }

  /**
   * fn:验证商户是否可用
   * @returns {Promise<void>}
   */
  async verificationMtchOutTradeNo(obj, req){
    if(!obj || !obj.outTradeNo || !obj.mchtId || !obj.no){
      return this.getCodeResult(1002001,null);
    }
    let no = await this.getNo(obj.no);
    try {
      let _cCashInfo = await  this.ccashinfoSve.getBean({
        id: no,
        outTradeNo: this.trim(obj.outTradeNo),
        mchtId: this.trim(obj.mchtId),
      })||{};

      let resData = {
        id_name:_cCashInfo.id_name,
        id_no:_cCashInfo.id_no,
      };
      this.ccashinfoSve.formatStatus(resData,_cCashInfo);
      return this.getCodeResult(0, resData);
    }catch (e) {
      console.log(e);
      let result = {
        code: 500,
        msg: "接口异常"
      };
      console.log(e.stack);
      return result;
    }
  }

  /**
   * fn:个人要素认证
   * @returns {Promise<void>}
   */
  async authentication(obj, req){
    if(!obj || !obj.id_name || !obj.id_no || !obj.no || !obj.openId){
      return this.getCodeResult(1002001,null);
    }
    let id = this.getNo(obj.no);
    try{
      let ccashinfo = await this.ccashinfoSve.getBean({
        id: id
      });
      if(!ccashinfo){
        return this.getErrResult("提现申请不存在");
      }
      if (!await this.idcardClient.checkIDCard(obj.id_no)) {
        return this.getErrResult("身份证格式不正确");
      }

      let num = await this.esettleSve.isValidAge([obj.mchtId]);
      if(num) {
        let card = await this.idcardClient.cardInfo(obj.id_no);
        let age = card.age || 0;
        if(!age) {
          return this.getErrResult("身份证号格式错误, 只支持18位身份证号码");
        }
        if(card.sex == 'male') {
          if (age < 18 || age > 60) {
            return this.getErrResult("签约失败，男限制18-60岁之间")
          }
        } else {
          if (age < 18 || age > 55) {
            return this.getErrResult("签约失败，女限制18-55岁之间")
          }
        }
      }
      /**
       * TODO:需要线上测试
       */
      let doAuthRes =await this.doAuth({id_name:this.trim(obj.id_name),id_no:this.trim(obj.id_no), app_id:obj.app_id});
      if (doAuthRes.status !== 0) {
        return this.getBaseResult(1, doAuthRes.msg || "姓名或身份证错误");
      }
      ccashinfo.id_name = this.trim(obj.id_name);
      ccashinfo.id_no = this.trim(obj.id_no);
      ccashinfo.openId = this.trim(obj.openId);
      await ccashinfo.save();
      // console.log("调用二要素 （兰伯望） 接口返回："+JSON.stringify(doAuthRes));
      this.doSign3(ccashinfo);
      return { code:0, msg:"认证成功", data:{amt:system.f2y(ccashinfo.amt),mchtId:ccashinfo.mchtId}};
    }catch (e) {
      console.log(e);
      let result = {
        code: 500,
        msg: "接口异常"
      };
      console.log(e.stack);
      return result;
    }
  }

  /**
   * fn:打开红包
   * @param obj
   */
  async openRedEnvelopes(obj){
    if(!obj.no){
      return this.getBaseResult(1, 'ID不能为空');
    }
    let id = this.getNo(obj.no);
    let ccashinfo = await this.ccashinfoSve.getBean({
      id: id
    }) || {};

    let key = `SDPJ_CASH_${ccashinfo.id}`;
    let _lock = uuidv1();
    try {
      if (!ccashinfo) {
        return this.getErrResult("信息不存在");
      }

      if (ccashinfo.qrcode_status != 1) {
        return this.getErrResult("二维码已作废，禁止提现");
      }

      if (ccashinfo.trade_status) {
        return this.getErrResult("已提现，不要重复提现");
      }

      let api = await this.ecompanybusiSve.findOne({
        appId: ccashinfo.app_id,
        etemplate_id: ccashinfo.ecid,
        mchtId: ccashinfo.mchtId,
      });

      await this.redisLock.lock(key, _lock, 20);
      let result = await this.cashOut(ccashinfo, api);
      return result;
    } catch (e) {
      console.log(e);
      let result = {
        code: 500,
        msg: "接口异常"
      };
      console.log(e.stack);
      return result;
    } finally {
      await this.redisLock.unLock(key, _lock);
    }
  }

  async doAuth(cashInfo) {
    let res;
    // 姓名二要素
    res = await this.bankthreelogSve.personTwo({
      appId: "sdpj_sign_" + cashInfo.app_id,
      userName: cashInfo.id_name,
      userIdNo: cashInfo.id_no
    });
    return res;
  }

  async doSign3(cashInfo) {
    let result;
    // 专票签（三方签）
    let signParam = {
      ecid: this.trim(cashInfo.ecid),
      appId: this.trim(cashInfo.app_id),
      userId: this.trim(cashInfo.id_no),
      idName: this.trim(cashInfo.id_name),
      idNo: this.trim(cashInfo.id_no),
    };
    try {
      let key = `${cashInfo.mcthId}_${cashInfo.outTradeNo}`;
      let id = uuidv1();
      await this.redisLock.lock(key, id, 20);
      let result = await this.econtractSve.autoSignBankTwo(signParam);
      await this.redisLock.unLock(key, id);

      if (result.data && result.data.contractId) {
        cashInfo.contract_id = result.data.contractId;
        cashInfo.save();
      }
      return result;
    } catch (e) {
      console.log(e, cashInfo, "-----------------------签约异常-----------------------");
      return {code: 1, msg: "签约异常"};
    }
  }

  async cashOut(cashInfo, api) {
    // 发起交易
    let bizContent = [];
    bizContent.push({
      "note": "提现",
      "idType": "00",
      "idName": cashInfo.id_name,
      "seqNo": "1000",
      "accNo": cashInfo.openId,
      "amt": cashInfo.amt,
      "accType": "02",
      "idNo": cashInfo.id_no
    });
    let nonceStr = await this.getUidStr(32, 36);
    let tradeTime = moment().format('YYYYMMDDHHmmss');
    let param = {
      "appId": cashInfo.app_id,
      "currency": "CNY",
      "mchtId": cashInfo.mchtId,
      "nonceStr": nonceStr,
      "notityUrl": "https://bpohhr.gongsibao.com/api/bpoSDPJApi/wxnotify",
      "outTradeNo": cashInfo.outTradeNo,
      "signType": "MD5",
      "tradeTime": tradeTime,
      "bizContent": bizContent,
    };

    // now
    let signArr = [];
    signArr.push("appId=" + param.appId);
    signArr.push("currency=" + param.currency);
    signArr.push("mchtId=" + param.mchtId);
    signArr.push("nonceStr=" + param.nonceStr);
    signArr.push("notityUrl=" + param.notityUrl);
    signArr.push("outTradeNo=" + param.outTradeNo);
    signArr.push("signType=" + param.signType);
    signArr.push("tradeTime=" + param.tradeTime);
    signArr.push("key=" + api.key);
    param.sign = md5(signArr.join("&")).toUpperCase();
    console.log(JSON.stringify(param));

    try {
      let rs = await axios({
        method: 'post',
        url: settings.apiconfig.payDomain() + "/merchant/order/transfer",
        data: param,
      });
      let resData = {amt: system.f2y(cashInfo.amt)};
      if (rs.data.code === 0) {
        cashInfo.trade_status = "01";
        cashInfo.trade_desc = "提现申请成功";
        await cashInfo.save();

        this.ccashinfoSve.formatStatus(resData, cashInfo);
        return this.getSuccessResult("提现成功", resData);
      } else {
        cashInfo.trade_status = "02";
        cashInfo.trade_desc = rs.data.msg || "提现申请失败";
        await cashInfo.save();
        this.ccashinfoSve.formatStatus(resData, cashInfo);
        this.notifyCash(cashInfo.id);
        return this.getSuccessResult(cashInfo.trade_desc, resData);
      }
    } catch (error) {
      console.log(error);
      return this.getErrResult("接口异常");
    }
  }

  async getUidStr(len, radix) {
    var chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');
    var uuid = [],
      i;
    radix = radix || chars.length;
    if (len) {
      for (i = 0; i < len; i++) uuid[i] = chars[0 | Math.random() * radix];
    } else {
      var r;
      uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
      uuid[14] = '4';
      for (i = 0; i < 36; i++) {
        if (!uuid[i]) {
          r = 0 | Math.random() * 16;
          uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
        }
      }
    }
    return uuid.join('');
  }

  async wxnotify(obj, req) {
    console.log("------------- wx-sdpj转账回调 --------------" , obj);
    try {
      // 1. 获取转账二维码信息
      let cashInfo = await this.ccashinfoSve.findOne({
        app_id: obj.appId,
        mchtId: obj.busiId,
        outTradeNo: obj.outTradeNo,
      });
      if (!cashInfo) {
        console.log("------------- wx-sdpj转账回调 cashInfo不存在--------------");
        return {code: ""};
      }
      if (cashInfo.trade_status == "00") {
        return {code: "0000"};
      }

      console.log("------------- wx-sdpj转账回调 cashInfo --------------", cashInfo);

      // 获取商户api信息
      let api = await this.ecompanybusiSve.findOne({
        appId: cashInfo.app_id,
        etemplate_id: cashInfo.ecid,
        mchtId: cashInfo.mchtId,
      });
      console.log("------------- wx-sdpj转账回调 api --------------", api);
      if (!api) {
        console.log("------------- wx-sdpj转账回调 api不存在--------------");
        return {code: ""};
      }

      // 验证签名
      let sign = system.getSign(obj, api.key, this.EXCEPT_KEYS);
      console.log("------------- wx-sdpj转账回调 签名 --------------", obj.sign, sign);
       if (sign != obj.sign) {
        console.log("------------- wx-sdpj转账回调 签名错误 --------------");
        return {code: ""};
      }

      // 回调逻辑判断
      let respCode = this.trim(obj.respCode);
      if (respCode == "00") {
        cashInfo.trade_status = "00";
        cashInfo.trade_desc = "交易成功";
        await cashInfo. save();
        this.notifyCash(cashInfo.id);
        return {code: "0000"};
      } else if (respCode == "02") {
        cashInfo.trade_status = "02";
        cashInfo.trade_desc = obj.respDesc || "交易失败";
        await cashInfo.save();
        this.notifyCash(cashInfo.id);
      } else {
      }
      return {code: ""};
    } catch (e) {
      console.log(e);
    }
  }

  // 通过postman推送回调
  async notifyGuestById(obj, req) {
    let res =await this.notifyCash(obj.no);
    return this.getBaseResult(0, "调用成功", res);
  }

  // 推送回调
  async notifyCash(id) {
    try { // 签名验证
      if(!id){
        return this.getErrResult("ID不能为空");
      }
      let ccashinfo = await this.ccashinfoSve.findOne({
        id:id
      });
      if(!ccashinfo.app_id){
        return this.getErrResult("app_id不能为空");
      }
      if(!ccashinfo.ecid){
        return this.getErrResult("ecid不能为空");
      }
      if(!ccashinfo.outTradeNo){
        return this.getErrResult("outTradeNo不能为空");
      }
      if(!ccashinfo.amt){
        return this.getErrResult("amt不能为空");
      }
      // if(!ccashinfo.id_name){
      //   return this.getErrResult("id_name不能为空");
      // }
      // if(!ccashinfo.id_no){
      //   return this.getErrResult("id_no不能为空");
      // }
      if(!ccashinfo.notify_url){
        return this.getErrResult("notify_url不能为空");
      }
      // 获取api信息
      let api = await this.ecompanybusiSve.findOne({
        appId: ccashinfo.app_id,
        etemplate_id: ccashinfo.ecid,
        mchtId: ccashinfo.mchtId,
      });
      if (!api) {
        return this.getBaseResult(1001003, "配置信息错误，请联系薪必果人员进行配置");
      }

      let param = {
        appId: ccashinfo.app_id,
        ecid: ccashinfo.ecid,
        outTradeNo: ccashinfo.outTradeNo,
        amt: ccashinfo.amt,
        idName: ccashinfo.id_name,
        idNo: ccashinfo.id_no,
        tradeStatus:ccashinfo.trade_status,
        nonceStr:await this.getUidStr(32, 36),
      };
      let sign=system.getSign(param, api.key, this.EXCEPT_KEYS)
      param.sign=sign;
      let rs = await axios({
        method: 'post',
        url:ccashinfo.notify_url,
        data: param,
      });
      return rs.data;
    } catch (e) {
      console.log(e);
      let result = {
        code: 500,
        msg: "接口异常"
      };
      console.log(e.stack);
      return result;
    }
  }

  getSuccessResult(msg = "success", data = {}) {
    return this.getBaseResult(0, msg, data);
  }

  getCodeResult(code, data={}){
    return this.getBaseResult(code, this.resultMap[code], data);
  }

  getErrResult(msg){
    return this.getBaseResult(1, msg);
  }

  getBaseResult(code, msg, data) {
    let res = {
      "code": code,
      "msg": msg,
      "data": data
    };
    return res;
  }
}
module.exports = BpoSDPJApi;
