const system = require("../../../system");
const ServiceBase = require("../../svems.base");
const settings = require("../../../../config/settings");
const fs = require("fs");
const xlsx = require('node-xlsx');

class TradeService extends ServiceBase {
  constructor() {
    super();
    // this.businessmenSve = system.getObject("service.business.businessmenSve");
    this.merchantSve = system.getObject("service.saas.merchantSve");
    this.orderSve = system.getObject("service.saas.orderSve");
    this.redisClient = system.getObject("util.redisClient");
  }

  async orderPage(params) {
    params.currentPage = Number(params.currentPage || 1);
    params.pageSize = Number(params.pageSize || 10);
    let rs = await this.callms("trade", "orderPage", params) || {};
    if (rs.data && rs.data.rows) {
      this.transFields(rs.data.rows);
    }
    return rs;
  }

  async orderInfo(params) {
    let rs = await this.callms("trade", "orderInfo", params) || {};
    let order = rs.data;
    if (order) {
      this.transFields([order]);
      let merchant = await this.merchantSve.info({id: params.saas_merchant_id}) || {};
      merchant = merchant.data || {};
      order.merchant_name = merchant.name;
    }
    return rs;
  }

  async itemPage(params) {
    params.currentPage = Number(params.currentPage || 1);
    params.pageSize = Number(params.pageSize || 10);
    let rs = await this.callms("trade", "itemPage", params) || {};
    if (rs.data && rs.data.rows) {
      this.transFields(rs.data.rows);
    }
    return rs;
  }

  async lockOrder(params) {
    let order_type = this.trim(params.order_type);
    if (["10", "20"].indexOf(order_type) == -1) {
      return system.getResult(null, `order_type[${params.order_type || null}]设置错误`)
    }
    params.acc_type = this.trim(params.acc_type);
    params.fileUrl = this.trim(params.fileUrl);
    let itemList = params.itemList || [];
    if (["00", "01", "02"].indexOf(params.acc_type) == -1) {
      return system.getResultFail(-1, `请选择打款通道`, itemList);
    }

    if (itemList.length == 0) {
      return system.getResultFail(-1, `锁定批次无数据`, itemList);
    }
    // 验证字段
    let error = await this.checkItemList(itemList, params);
    if (error) {
      return system.getResultFail(-1, `批次内有错误数据，请检查后修改`, itemList);
    }
    // 获取商户签约信息
    let info = await this.merchantSve.signInfo({id: params.saas_merchant_id}) || {};
    info = info.data || {};
    let main = info.main_trade || {};
    // 计算预计付款金额
    let result = await this.countAmt(itemList, info, params);

    let current = new Date();

    let projectName;
    for (let item of itemList) {
      item.amt = system.y2f(item.actual_amt);
      item.actual_amt = system.y2f(item.actual_amt);
      item.deduct_amt = system.y2f(item.deduct_amt);
      item.service_tax = system.y2f(item.service_tax);
      item.trade_status = "01";

      if (order_type == "20") {
        item.trade_time = current;
        item.trade_status = "00";
        item.trade_desc = "商户自行交易";
      }
      projectName = item.project_name;
    }

    let out_trade_no = await this.redisClient.genrateId("gsb_out_trade_no");
    // 构建批次对象
    let order = {
      saas_id: params.saas_id,
      saas_merchant_id: params.saas_merchant_id,
      out_trade_no: out_trade_no,
      service_rate: system.y2f(info.trans_service_rate),
      amt: system.y2f(result.actual_amt),
      actual_amt: system.y2f(result.actual_amt),
      deduct_amt: system.y2f(result.deduct_amt),
      service_tax: system.y2f(result.service_tax),
      item_count: itemList.length,
      acc_type: params.acc_type,
      order_file: params.fileUrl,
      order_type: order_type,
      project_name: projectName,
      // 付款凭证信息
      pay_voucher: "",
      pay_bank_account: main.bank_account,
      pay_bank_name: main.bank_name,
      pay_bank_no: main.bank_no,
      itemList: itemList
    };

    // 商户交易上传
    if (order_type == "20") {
      order.trade_status = "00";
      order.check_status = "05";
      order.check1_remark = "商户自行交易";
      order.check2_remark = "商户自行交易";
    }
    let rs = await this.callms("trade", "orderAdd", order);
    if (rs.data) {
      this.transFields([rs.data]);
    }
    return rs;
  }

  async offlinePay(params) {
    params.type = "offline";
    params.pay_voucher = this.trim(params.pay_voucher);
    params.pay_bank_account = this.trim(params.pay_bank_account);
    params.pay_bank_name = this.trim(params.pay_bank_name);
    params.pay_bank_no = this.trim(params.pay_bank_no);
    if (!params.pay_voucher) {
      return system.getResult(null, "请上传凭证");
    }
    let rs = await this.callms("trade", "orderPay", params);
    return rs;
  }

  async parseItems(params) {
    params.order_type = this.trim(params.order_type);
    if (["10", "20"].indexOf(params.order_type) == -1) {
      return system.getResult(null, `order_type[${params.order_type || null}]设置错误`)
    }

    // 获取商户签约信息
    let info = await this.merchantSve.signInfo({id: params.saas_merchant_id}) || {};
    info = info.data || {};
    if (!info.main_trade || !info.main_trade.id) {
      return system.getResult(null, "签约时未设置转账交易签约主体，请联系平台进行设置");
    }

    // 读取excel
    let itemList = await this.readItems(params);

    // 验证字段
    let error = await this.checkItemList(itemList, params);

    // 计算预计付款基恩
    let result = await this.countAmt(itemList, info, params);

    result.order_type = params.order_type;
    // 封装返回对象
    result.error = error;
    if (result.error) {
      // 处理错误信息
      for (let idx = 0; idx < itemList.length; idx++) {
        let item = itemList[idx];
        if (item.errors && item.errors.length > 0) {
          let len = Number(idx) + 7;
          return system.getResult(null, `第${len}行错误，` + item.errors.join("、"));
        }
      }
    }
    result.itemList = itemList;
    return system.getResultSuccess(result);
  }

  async countAmt(itemList, info, params) {
    let result = {amt: 0, actual_amt: 0, deduct_amt: 0, service_tax: 0};
    if (!itemList) {
      return result;
    }

    // 服务费，这里已经处理了分转元，不用在处理
    let service_rate = info.trans_service_rate;

    // 计算金额
    for (let data of itemList) {
      let amt = Number(data.amt);
      data.service_tax = parseFloat((amt * service_rate) / 100).toFixed(2);
      data.actual_amt = parseFloat(amt).toFixed(2);
      data.deduct_amt = parseFloat(Number(data.actual_amt) + Number(data.service_tax)).toFixed(2);

      // 总服务费
      result.service_tax = Number(result.service_tax) + Number(data.service_tax);
      // 总实发
      result.actual_amt = Number(result.actual_amt) + Number(data.actual_amt);
      // 总请求打款
      result.amt = Number(result.amt) + amt;
    }
    // 总扣款
    result.deduct_amt = Number(result.service_tax) + Number(result.actual_amt);
    return result;
  }

  async readItems(params) {
    let fileUrl = params.fileUrl;
    let fileName = params.fileName;
    let itemList = [];
    let filePath = settings.localpath() + "saas_xgg_trade_order_" + this.trim(fileName) + ".xlsx";
    try {
      // await this.downloadFile(params.url, filePath);
      await this.restClient.execDownload2(fileUrl, filePath);

      let sheets = xlsx.parse(filePath);
      fs.unlinkSync(filePath);

      if (!sheets || sheets.length == 0) {
        return system.getResult(null, "打款文件无数据")
      }
      let sheet = sheets[0];
      if (!sheet || !sheet.data || sheet.data.length == 0) {
        return system.getResult(null, "打款文件无数据")
      }
      let rows = sheet.data;
      let projectRow = rows[2];
      let projectName = projectRow.length >= 2 ? projectRow[1] : "";

      let itemList = [];
      for (let idx = 6; idx < rows.length; idx++) {
        var data = {
          errors: []
        };

        let cells = rows[idx];
        let cellLength = cells.length;
        if (cellLength == 0) {
          continue;
        }
        if (cellLength < 6) {
          data.errors.push("缺少数据, 列数不全");
          continue;
        }
        data.project_name = projectName;
        data.acc_name = this.trim(cells[1]);
        data.credit_code = this.trim(cells[2]).toUpperCase();
        data.acc_no = this.trim(cells[3]);
        data.open_bank = this.trim(cells[4]);
        data.amt = this.trim(cells[5]);
        if (cellLength == 6) {
          data.remark = "";
        } else {
          data.remark = this.trim(cells[6]);
        }
        itemList.push(data);
      }

      return itemList;
    } catch (error) {
      console.log(error);
      return system.getResult(null, "excel解析出错")
    }
  }

  async checkItemList(itemList, params) {
    let saas_merchant_id = params.saas_merchant_id;
    let error = false;
    if (!itemList || itemList.length == 0) {
      return system.getResult(null, "打款文件无数据")
    }

    // 统一社会信用代码获取
    let creditCodes = [];
    for (let data of itemList) {
      creditCodes.push(data.credit_code);
    }

    let creditCodeMap = await this.orderSve.mapByCreditCodes({
      saas_merchant_id: saas_merchant_id,
      creditCodes: creditCodes,
      attrs: "credit_code"
    });

    let order_type = this.trim(params.order_type);
    let amtName = "商户请求打款金额";
    if (order_type == "20") {
      amtName = "实发金额";
    }
    for (let data of itemList) {
      this.checkField(data, "acc_name", {name: "收款户名", is_require: true, maxLen: 64});
      let bm = creditCodeMap[data.credit_code];
      if (!bm) {
        data.errors.push(`统一社会信用代码[${data.credit_code}]不存在`);
      }
      this.checkField(data, "credit_code", {name: "个体户统一信用代码", is_require: true, eqLen: 18});
      this.checkField(data, "acc_no", {name: "收款账号", is_require: true, maxLen: 30, is_number: true});
      this.checkField(data, "open_bank", {name: "开户银行全称", maxLen: 100});
      this.checkField(data, "amt", {name: amtName, is_require: true, maxLen: 100, is_number: true});
      this.checkField(data, "remark", {name: "备注", maxLen: 100});

      if (!error && data.errors.length > 0) {
        error = true;
      }
    }
    return error;
  }

  async byIds(params) {
    let rs = await this.callms("trade", "itemByIds", params);
    return rs;
  }

  async updateInvoice(params) {
    let rs = await this.callms("trade", "updateItemInvoice", params);
    return rs;
  }

  async saveStPay(params) {
    let rs = await this.callms("trade", "saveStPay", params);
    return rs;
  }

  async updatePayStatus(params) {
    let rs = await this.callms("trade", "updateStatus", params);
    return rs;
  }

  checkField(data, field, rule) {
    if (!data || !field) {
      return;
    }
    data.errors = data.errors || [];
    let v = data[field];
    if (rule.is_require && !v) {
      data.errors.push(`${rule.name}未填写`);
    }
    if (rule.maxLen && v.length > rule.maxLen) {
      data.errors.push(`${rule.name}长度不允许超过${rule.maxLen}`);
    }
    if (rule.minLen && v.length < rule.minLen) {
      data.errors.push(`${rule.name}长度不允许少于${rule.minLen}`);
    }
    if (rule.eqLen && v.length != rule.eqLen) {
      data.errors.push(`${rule.name}长度为${rule.eqLen}`);
    }
    if (rule.is_number && isNaN(v)) {
      data.errors.push(`${rule.name}需要填写数字类型`);
    }
  }

  transFields(rows) {
    if (!rows || rows.length == 0) {
      return;
    }

    for (let row of rows) {
      row.amt = system.f2y(row.amt);
      row.actual_amt = system.f2y(row.actual_amt);
      row.deduct_amt = system.f2y(row.deduct_amt);
      row.service_tax = system.f2y(row.service_tax);
      row.service_rate = system.f2y(row.service_rate);
    }
  }

  async invoiceTrade(params) {
    let rs = await this.callms("trade", "invoiceTrade", params) || {};
    return rs;
  }
}

module.exports = TradeService;