const { v4 } =require('uuid');
const moment = require("moment");
const iconvLite = require('iconv-lite');
const querystring = require('querystring');
const path = require("path");
const { remote } = require("electron");
var qr = require('qr-image');
var fs = require('fs');
var JsBarcode = require('jsbarcode');
var big = require('big.js');

/**
 * 将一个秒数值转换为  天:时:分:秒 格式
 * @param {*} time 表示秒数
 */
function calcParkingDuration(time) {
  var result = {
    Days: 0,
    Hours: 0,
    Minutes: 0,
    Seconds: 0,
  };
  if (!time) {
    return result;
  }

  var res = '';
  result.Days = Math.floor(time / (24 * 3600));
  time = time % (24 * 3600);

  result.Hours = Math.floor(time / 3600);
  time = time % 3600;

  result.Minutes = Math.floor(time / 60);
  time = Math.floor(time % 60);

  result.Seconds = time;
  return result;
}
/**
 * 将最小单位的金额转换成相应国家的基本单位。
 * @param {*} money
 */
function convertMoney(money, precision, defaultValue) {
  precision = parseInt(precision);
  if (isNaN(precision)) {
    precision = 2;
  }
  if (defaultValue == undefined) {
    defaultValue = 0;
  }
  money = parseFloat(money);
  if (isNaN(money) || money == null) {
    return defaultValue.toFixed(precision);
  }
  return (money / 100).toFixed(precision);
}

/**
 * 金额精确转换
 * @param money 金额（默认：分）
 * @param div 金额换算值
 * @param point 保留小数点后几位
 * @returns {string}
 */
function convertBigMoney(money,div = 100,point = 2) {
  return new big(money).div(div).toFixed(point);
}

/**
 * 金额汇率转换
 * @param money 金额
 * @param exchangeRate 汇率
 * @returns {*}
 */
function currencyMoney(money, exchangeRate) {
  return new big(money).times(parseFloat(exchangeRate)).toString();
}
/**
 * 序列化JSON对象,并格式化
 * @param {*} jsonObj
 */
function formatJson(jsonObj) {
  return JSON.stringify(jsonObj, ' ', 4);
}
/**
 * 将JSON对象转换为key1=value&key2=value&key3=value形式
 * @param {*} obj
 */
function jsonToQueryString(obj) {
  var toString = Object.prototype.toString;
  if (toString.call(obj) != '[object Object]') {
    return '';
  }
  return querystring.stringify(obj);
}
/**
 * 生成Guid
 * @param {*} style style: 表示Guid表示形式 1:小写字母+- 2:大写字母+- 3:纯小写字母 4:纯大写字母
 */
function guid(style) {
  if (style == undefined || style == null || isNaN(style)) {
    style = 1;
  }
  var strGuid = v4();
  if (style == 1) {
    return strGuid;
  } else if (style == 2) {
    return strGuid.toUpperCase();
  } else if (style == 3) {
    return strGuid.replace(/-/g, '');
  } else if (style == 4) {
    return strGuid.toUpperCase().replace(/-/g, '');
  } else {
    return strGuid;
  }
}
/**
 * 将Buffer转换为相应的字符串
 * @param {*} 字符编码(UTF-8、GBK、GB2312、GB18030)
 */
function bufferToString(bufferData, encoding) {
  if (
    !Buffer.isBuffer(bufferData) &&
    !Object.toString.call(bufferData) == '[object Array]'
  ) {
    return '';
  }
  if (!Buffer.isBuffer(bufferData)) {
    bufferData = Buffer.from(bufferData);
  }
  if (encoding.toUpperCase() == 'UTF-8') {
    return bufferData.toString();
  } else if (
    encoding.toUpperCase() == 'GBK' ||
    encoding.toUpperCase() == 'GB2312' ||
    encoding.toUpperCase() == 'GB18030'
  ) {
    return iconvLite.decode(bufferData, encoding);
  }
  if (iconvLite.encodingExists(encoding)) {
    return iconvLite.decode(bufferData, encoding);
  } else {
    throw new error(`解码失败,不支持解码:${encoding}数据`);
  }
}
/**
 * 将字符串内容转换为Buffer
 * @param {*} str 需要被转换为字符串的内容
 * @param {*} encoding 编码
 */
function stringToBuffer(str, encoding) {
  if (encoding == undefined || encoding == null) {
    encoding = 'UTF-8';
  }
  if (encoding == 'UTF-8') {
    return Buffer.from(str, encoding);
  } else {
    if (iconvLite.encodingExists(encoding)) {
      return iconvLite.encode(str, encoding);
    }
    else {
        throw new error(`编码失败,不支持的编码:${encoding}`);
    }
  }
}
/**
 * 将数据转换为base64字符串
 * @param {*} obj
 */
function bufferToBase64(obj) {
  var toString = Object.prototype.toString;
  if (
    Buffer.isBuffer(obj) ||
    Array.isArray(obj) ||
    toString.call(obj) == '[object Array]' ||
    toString.call(obj) == '[object String]'
  ) {
    return Buffer.from(obj).toString('base64');
  } else {
    return null;
  }
}
/**
 * 获取当前系统时间
 */
function currentTime() {
  return moment();
}
/**
 * 获取当前系统IP地址
 */
function getIP() {
  var os = require('os');
  var ifaces = os.networkInterfaces();
  for (var prop in ifaces) {
    for (var j = 0; j < ifaces[prop].length; j++) {
      var iface = ifaces[prop][j];
      if ('IPv4' !== iface.family || iface.internal !== false) {
        continue;
      }
      return iface.address;
    }
  }
}
/**
 * 获取指定范围内的随机数
 * @param {*} min 最小数
 * @param {*} max 最大数
 */
function getRandom(min, max) {
  return Math.floor(Math.random() * (max - min)) + min;
}
/**
 * 生成二维码图片(.png)
 * @param qrString 生成二维码文本
 * @param savePath 图片保存路径
 * @param imgName 图片名称
 * @param imgLevel 纠错级别（L,M,Q,H 默认M）
 * @param imgSize 图片大小(默认5)
 * @param imgMargin 二维码边框宽度（默认1）
 * @returns {Promise<unknown>}
 */
async function createQrCodeImg(qrString,savePath,imgName,imgLevel = 'M',imgSize = '5',imgMargin = '1') {
  return new Promise(function (resolve) {
    var code = qr.image(qrString, { ec_level: imgLevel,type: 'png', size: parseInt(`${imgSize}`),margin:parseInt(`${imgMargin}`) });
    if (!fs.existsSync(savePath)) {
      fs.mkdirSync(savePath);
    }
    //生成本地文件
    var pic = code.pipe(fs.createWriteStream(`${savePath}/${imgName}.png`));
    //监听错误事件
    pic.on('error', (err)=> {
      console.log(`二维码图片生成失败error：${err}`);
      resolve("");
    });
    //监听完成事件
    pic.on('finish', ()=> {
      let imgPath = path.join(savePath, `${imgName}.png`);
      console.log(`二维码图片生成成功，图片路径${imgPath}`);
      resolve(imgPath);
    });
  });
}
/**
 * 生成一维码图片（.png）
 * @param barString 生成一维码文本
 * @param savePath 图片保存路径
 * @param imgName 图片名称
 * @param barWidth 每个条条的宽度（默认2）
 * @param barHeight 整个条形码的高度（默认50）
 * @param barTextDisplay 是否显示条形码下面的文字（默认true）
 * @param barTextFontSize 设置条形码文本的字体大小（默认15）
 * @returns {Promise<unknown>}
 */
async function createBarCodeImg(barString,savePath,imgName,barWidth = '2',barHeight = '50',barTextDisplay = true,barTextFontSize = '15') {
  return new Promise(function (resolve) {
    var canvas = document.createElement("canvas");
    JsBarcode(canvas, barString, {
      width: barWidth,
      height: barHeight,
      displayValue: barTextDisplay,
      fontSize:barTextFontSize
    });
    try {
      if (!fs.existsSync(savePath)) {
        fs.mkdirSync(savePath);
      }
      var str = canvas.toDataURL();
      var imgBase64Str = str.split(",")[1];
      var imageBuffer = Buffer.from(imgBase64Str, "base64");
      let imgPath = path.join(savePath, `${imgName}.png`);
      fs.writeFileSync(`${savePath}/${imgName}.png`, imageBuffer);
      console.log(`一维码图片生成成功，图片路径${imgPath}`);
      resolve(imgPath);
    } catch (err) {
      console.log(`一维码图片生成失败error：${err}`);
      resolve(err);
    }
  });
}

/**
 * 根据printObj参数生成1位BMP图片
 * @param printObj   width: 580,//画布宽度
                     height: 1000,//画布高度
                     startPrintX: 0,//每一行打印的开始位置(横坐标)
                     startPrintY: 30,//每一行打印的开始位置(纵坐标)
                     marginBottom: 12,//每一行之间的间隔高度。(可选)
                     footerHeight: 12,//小票底部留白高度。
                     fontStyle: 'normal',//normal | italic | oblique | inherit
                     fontWeight: 'normal',//normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | inherit | auto
                     fontSize: 30,//字体大小(可选)
                     fontFamily: "Arial",//打印所需使用的字体(可选)
                     printItems: [
                     {
                              printText: "",//需要打印的文本(必填)
                              itemType: 1,//打印类型，1：文本 2：图片, 默认[1]。(可选)
                              align: 0,//对齐方式 0：居左 1：居中 2：居右,默认[0]。(可选)
                              startPrintX: 100,//从横坐标那个位置开始打印。(可选)
                              marginBottom: 0,//距离下一行的空白行的高度,默认[10](可选)
                              fontSytle: "",//字体样式,默认[正常](可选),可用的值：normal | italic | oblique | inherit
                              fontWeight: "",//是否加粗,默认[不加粗](可选),可用的值：normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | inherit | auto
                              fontFamily: "",//字体类别,(可选)
                              fontSize: 0,//字体大小,默认20px(可选)
                            }
                     ]
 * @returns {Promise<unknown>}
 */
async function createPrintBMP(printObj) {
  return new Promise(async function (resolve) {
    var returnResult = {
      IsSuccess: false,
      Data: null,
      Message: ""
    };
    var printTemplate = {
      width: 580,//画布宽度
      height: 1000,//画布高度
      startPrintX: 0,//每一行打印的开始位置(横坐标)
      startPrintY: 30,//每一行打印的开始位置(纵坐标)
      marginBottom: 12,//每一行之间的间隔高度。(可选)
      footerHeight: 12,//小票底部留白高度。
      fontStyle: 'normal',//normal | italic | oblique | inherit
      fontWeight: 'normal',//normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | inherit | auto
      fontSize: 30,//字体大小(可选)
      fontFamily: "Arial",//打印所需使用的字体(可选)
      printItems: [
        {
          printText: "",//需要打印的文本(必填)
          itemType: 1,//打印类型，1：文本 2：图片, 默认[1]。(可选)
          align: 0,//对齐方式 0：居左 1：居中 2：居右,默认[0]。(可选)
          startPrintX: 100,//从横坐标那个位置开始打印。(可选)
          marginBottom: 0,//距离下一行的空白行的高度,默认[10](可选)
          fontSytle: "",//字体样式,默认[正常](可选),可用的值：normal | italic | oblique | inherit
          fontWeight: "",//是否加粗,默认[不加粗](可选),可用的值：normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | inherit | auto
          fontFamily: "",//字体类别,(可选)
          fontSize: 0,//字体大小,默认20px(可选)
        }
      ]
    };
    var canvas = document.createElement("canvas");
    var context = canvas.getContext("2d");
    context.fillStyle = "#FFFFFF";
    if (!printObj.hasOwnProperty("fontStyle")) {
      printObj.fontStyle = printTemplate.fontStyle;
    }
    if (!printObj.hasOwnProperty("fontWeight")) {
      printObj.fontWeight = printTemplate.fontWeight;
    }
    if (!printObj.hasOwnProperty("fontSize")) {
      printObj.fontSize = printTemplate.fontSize;
    }
    if (!printObj.hasOwnProperty("fontFamily")) {
      printObj.fontFamily = printTemplate.fontFamily;
    }
    if (!printObj.hasOwnProperty("marginBottom")) {
      printObj.marginBottom = printTemplate.marginBottom;
    }
    if (!printObj.hasOwnProperty("startPrintX")) {
      printObj.startPrintX = printTemplate.startPrintX;
    }
    if (!printObj.hasOwnProperty("startPrintY")) {
      printObj.startPrintY = printTemplate.startPrintY;
    }
    if (!printObj.hasOwnProperty("width")) {
      printObj.width = printTemplate.width;
    }
    if (!printObj.hasOwnProperty("height")) {
      printObj.height = printTemplate.height;
    }
    if (!printObj.hasOwnProperty("footerHeight")) {
      printObj.footerHeight = printObj.marginBottom;
    }
    canvas.width = printObj.width;
    canvas.height = printObj.height;
    var printX = printObj.startPrintX;
    var printY = printObj.startPrintY;
    for (var i = 0; i < printObj.items.length; i++) {
      var printItem = printObj.items[i];
      if (!printItem.hasOwnProperty("fontStyle")) {
        printItem.fontStyle = printObj.fontStyle;
      }
      if (!printItem.hasOwnProperty("fontWeight")) {
        printItem.fontWeight = printObj.fontWeight;
      }
      if (!printItem.hasOwnProperty("fontSize")) {
        printItem.fontSize = printObj.fontSize;
      }
      if (!printItem.hasOwnProperty("fontFamily")) {
        printItem.fontFamily = printObj.fontFamily;
      }
      if (!printItem.hasOwnProperty("marginBottom")) {
        printItem.marginBottom = printObj.marginBottom;
      }

      context.font = printItem.fontStyle + " " + printItem.fontWeight + " " + printItem.fontSize + "px" + " " + printItem.fontFamily;
      var textMetrics = context.measureText(printItem.printText);
      context.textAlign = 'left';
      if (printItem.align == '1') {//居中
        context.textAlign = 'center';
        printX = canvas.width / 2;
      } else if (printItem.align == '2') {//居右
        printX = (canvas.width - textMetrics.width - 20);
      } else {//居左
        if (printItem.hasOwnProperty("startPrintX")) {
          printX = printItem.startPrintX;
        } else {
          printX = printObj.startPrintX;
        }
      }
      await printItemBMP(context,canvas,printObj,printItem, printX, printY).then(res=>{
        //不把最后一样的行高+下边距算入画布高度。
        if (i < printObj.items.length - 1) {
          printY += printItem.marginBottom + res;
        } else {
          printY += 2;
        }
      });
    }
    printObj.height = canvas.height + (printObj.footerHeight - (canvas.height - printY));
    setTimeout(function () {
      var str = canvas.toDataURL();
      var imgBase64Str = str.split(",")[1];
      var imageBuffer = Buffer.from(imgBase64Str, "base64");
      var filePath = path.resolve(path.join("./", "printImg.png"));
      fs.writeFileSync(filePath, imageBuffer)
      var pngFilePath = path.resolve(path.join("./", "printImgPNG.png"));
      var Jimp = remote ? remote.require("jimp"):require("jimp");
      var PNG = require("pngjs").PNG;
      fs.createReadStream(filePath)
          .pipe(new PNG({
            colorType: 0,
            bgColor: {
              red: 255,
              green: 255,
              blue: 255
            }
          }))
          .on('parsed', function () {
            try {
              this.pack().pipe(fs.createWriteStream(pngFilePath));
              setTimeout(function () {
                Jimp.read(pngFilePath).then(function (image) {
                  image.getBuffer("image/bmp", function (error, buffer) {
                    const Bmp = require('binary-bmp');
                    const bit = 24; // 颜色位值
                    const width = printObj.width; // 图片宽度
                    const height = printObj.height; // 图片高度
                    const data = buffer;
                    const bmp = new Bmp(bit, { width, height, data });
                    var newBuffer = bmp.getBuffer();
                    fs.writeFileSync("./printImgBMP24.bmp",newBuffer);
                    var currentDir = __dirname;
                    var sdkPath = path.join(currentDir, "./windows/BMPGeneratorUtil.dll");
                    if (process.platform == "linux" && process.arch == "arm") {
                      sdkPath = path.join(currentDir, "./linux/BMPGeneratorUtil.so");
                    }
                    const ffi = remote ? remote.require("ffi-napi") : require("ffi-napi");
                    const ref = remote ? remote.require("ref-napi") : require("ref-napi");
                    const printerUtil = ffi.Library(sdkPath,{
                      BMP_bit24_to_uv1: [ref.types.bool, ["string","string"]],
                      JPG_To_BMP24: [ref.types.bool, ["string","string"]],
                      JPG_To_BMP1:  [ref.types.bool, ["string","string"]],
                    });
                    setTimeout(function () {
                      if (printerUtil.BMP_bit24_to_uv1(path.resolve(path.join("./", "printImgBMP24.bmp")),path.resolve(path.join("./", "printImgBMP1.bmp")))) {
                        console.log('24位BMP图片转1位BMP图片成功!');
                        var printImeFile = path.resolve(path.join("./", "printImgBMP1.bmp"));
                        returnResult.IsSuccess = true;
                        returnResult.Data = printImeFile;
                        resolve(returnResult);
                      }
                    },500);
                  });
                });
              }, 500);
            } catch (error) {
              console.log('24位BMP图片转1位BMP图片失败!');
              returnResult.IsSuccess = false;
              returnResult.Message = error;
              resolve(returnResult);
            }
          });
    },500);
  })
}

function printItemBMP(context,canvas,printObj,printItem, printX, printY) {
  return new Promise(resolve => {
    if (printItem.itemType == '2') {
      try {
        var image = new Image();
        const fs = require('fs');
        fs.readFile(printItem.printText, 'base64', (err, data) => {
          image.src = 'data:image/png;base64,'+data;
          image.onload = function () {
            if (printItem.align == '1') {
              printX = ((canvas.width - image.width)/2);
            } else if (printItem.align == '2') {
              printX = (canvas.width - image.width - 20);
            } else {
              if (printItem.hasOwnProperty("startPrintX")) {
                printX = printItem.startPrintX;
              } else {
                printX = printObj.startPrintX;
              }
            }
            context.drawImage(image, printX, printY);
            resolve(image.height);
          }
        });
      } catch (e) {
        console.log(e)
      }
    } else {
      context.fillText(printItem.printText, printX, printY);
      resolve(0);
    }
  })
}

/**
 * 从指定Url下载文件,并保存
 * @param {*} url 文件http地址
 * @param {*} savePath 保存位置
 */
async function downloadFile(url, savePath) {
  return new Promise(function (resolve) {
    let result = {
      success: false,
      message: '',
    };
    let fs = require('fs');
    if (url.startsWith('https')) {
      let https = require('https');
      let req = https.request(
        url,
        {
          rejectUnauthorized: false,
        },
        function (resp) {
          let stream = fs.createWriteStream(`${savePath}`);
          resp.pipe(stream);
          stream.on('finish', function () {
            result.success = true;
            stream.close();
            resolve(result);
          });
        }
      );
      req.on('error', function (error) {
        result.success = false;
        result.message = error.message;
        resolve(result);
      });
      req.end();
    } else if (url.startsWith('http')) {
      let http = require('http');
      let req = http.request(url, {}, function (resp) {
        let stream = fs.createWriteStream(`${savePath}`);
        resp.pipe(stream);
        stream.on('finish', function () {
          result.success = true;
          stream.close();
          resolve(result);
        });
      });
      req.on('error', function (error) {
        result.success = false;
        result.message = error.message;
        resolve(result);
      });
      req.end();
    } else {
      result.message = `下载失败,URL格式错误(仅支持http和https)`;
      resolve(result);
    }
  });
}
module.exports = {
  calcParkingDuration,
  convertMoney,
  formatJson,
  jsonToQueryString,
  guid,
  bufferToString,
  stringToBuffer,
  currentTime,
  getIP,
  bufferToBase64,
  getRandom,
  printItemBMP,
  createQrCodeImg,
  createBarCodeImg,
  createPrintBMP,
  downloadFile,
};
