const fs = require('fs');
const path = require('path');
const ktHttp = require('@keytop/kthttp');
const AdmZip = require('adm-zip');
const moment = require('moment');
var timerHandle = null;
var isSync = false;
var isClear = false;
var options = {};
/**
 * 日志文件上传功能
 * @param {String} logRootDir 日志文件所在目录
 * @param {String} uploadUrl 日志文件需要上传到那个位置
 * @param {String} version 程序版本号
 */
function KtLogUploader(logRootDir, uploadUrl, version) {
  this.logRootDir = logRootDir;
  this.uploadUrl = uploadUrl;
  this.version = version;
  console.log(
    '日志上传远程Url:' + this.uploadUrl + ',日志根目录：' + this.logRootDir
  );
}
/**
 * 初始化日志服务(日志定时清理、定时上传)
 * options:{
 *  uploadTime:3,//定时上传日志的时间,必须>=-1&&<=23 其中-1:表示不开启日志定时上传服务.
 *  autoUploadLogCallback:()=>{},//定时上传日志上传完成后调用的回调函数。
 *  clearTime:3,//定时清理日志的时间,必须>=-1&&<=23 其中-1:表示不开启定时清理服务.
 *  keepDays:7//日志保留时间,默认为7天,必须>0
 *  clearPaths:[],//需要被清理的日志目录,日志文件根目录默认就会被自动清理,无需特别指定.
 * }
 * @param {*} options
 */
KtLogUploader.prototype.initLogService = function (options) {
  //debugger;
  var $this = this;
  var toString = Object.prototype.toString;
  if (toString.call(options) != '[object Object]') {
    options = {};
  }
  var clearTime = options.clearTime;
  var keepDays = options.keepDays;
  var uploadTime = options.uploadTime;
  var autoUploadLogCallback = options.autoUploadLogCallback;

  if (
    toString.call(uploadTime) != '[object Number]' ||
    uploadTime < -1 ||
    uploadTime > 23
  ) {
    uploadTime = -1;
  }
  if (toString.call(autoUploadLogCallback) != '[object Function]') {
    autoUploadLogCallback = function () {};
  }
  if (
    toString.call(clearTime) != '[object Number]' ||
    clearTime < -1 ||
    clearTime > 23
  ) {
    clearTime = 3;
  }
  if (toString.call(keepDays) != '[object Number]' || keepDays <= 0) {
    keepDays = 7;
  }
  if (toString.call(options.clearPaths) != '[object Array]') {
    options.clearPaths = [];
  }
  options.clearPaths.unshift(this.logRootDir);
  if (timerHandle) {
    clearInterval(timerHandle);
    timerHandle = null;
  }
  if (clearTime == -1 && uploadTime == -1) {
    return;
  }
  timerHandle = setInterval(function () {
    var currentHour = moment().hours();
    if (uploadTime != -1) {
      if (currentHour == uploadTime && !isSync) {
        isSync = true;
        console.log('准备定时上传日志!');
        $this
          .uploadLog(
            moment().subtract(1, 'days').format('YYYYMMDD'),
            '2',
            true,
            null,
            getIP(),
            [path.join($this.logRootDir, 'logs', moment().format('YYYYMMDD'))]
          )
          .then(function (result) {
            autoUploadLogCallback(result);
          });
      } else if (currentHour != uploadTime) {
        isSync = false;
      }
    }
    if (clearTime != -1) {
      if (currentHour == clearTime && !isClear) {
        isClear = true;
        console.log('准备清理' + keepDays + '天以前的日志!');
        ClearLogs(keepDays, options.clearPaths);
      } else if (currentHour != clearTime) {
        isClear = false;
      }
    }
  }, 1000);
};
function ClearLogs(keepDays, clearPaths) {
  let logDays = [];
  let startDate = moment().subtract(keepDays, 'days');
  for (var i = 0; i <= keepDays; i++) {
    logDays.push(startDate.format('YYYYMMDD'));
    startDate.add(1, 'days');
  }
  for (var m = 0; m < clearPaths.length; m++) {
    console.log(`准备清理目录:${clearPaths[m]}下的过期的日志文件`);
    let logFiles = getLogList(clearPaths[m]);
    let fileName = '';
    let fullPath = '';
    let isDelete = true;
    let deleteFiles = [];
    if (logFiles && logFiles.length > 0) {
      for (var i = 0; i < logFiles.length; i++) {
        fileName = logFiles[i].replace(/[\-/]/g, '');
        isDelete=true;
        for (var j = 0; j < logDays.length; j++) {
          if (fileName.indexOf(logDays[j]+".log") >= 0) {
            isDelete = false;
            break;
          }
        }
        if (isDelete) {
          deleteFiles.push(logFiles[i]);
          fullPath = path.join(clearPaths[m], logFiles[i]);
          deleteLogFile(fullPath);
        }
      }
    }
    console.log(
      '本次清理的日志文件如下:' + JSON.stringify(deleteFiles, ' ', 4)
    );
  }
}
/**
 * 启动日志自动上传功能。
 * @param {function} callback 定时上传成功后回调
 * @param {Number} uploadTime 定时上传的时间(小时部分,有效值:0-23)
 */
// KtLogUploader.prototype.startupAutoUploadLog = function (callback, uploadTime) {
//     var $this = this;
//     if (uploadTime == undefined || uploadTime == null || isNaN(uploadTime) || uploadTime == '' || (uploadTime < 0 || uploadTime > 23)) {
//         uploadTime = 3;
//     }
//     if (timerHandle) {
//         clearInterval(timerHandle);
//         timerHandle = null;
//     }
//     timerHandle = setInterval(function () {
//         //debugger;
//         var currentHour = new Date().getHours();
//         if (currentHour == uploadTime && !isSync) {
//             isSync = true;
//             console.log("准备定时上传日志!");
//             var yesterdayDate = subtractDays(new Date(), 1);
//             var month = (yesterdayDate.getMonth() + 1).toString().padStart(2, "0");
//             var date = yesterdayDate.getDate().toString().padStart(2, "0");
//             var yesterdayStr = yesterdayDate.getFullYear().toString() + month + date;
//             $this.uploadLog(yesterdayStr, 2).then(function (data) {
//                 if (Object.prototype.toString.call(callback) === "[object Function]") {
//                     callback(data);
//                 }
//             });
//         }
//         else if (currentHour != uploadTime) {
//             isSync = false;
//         }
//     }, 1000);
// }
/**
 * 上传指定日期的日志文件。
 * @param {string} logDate yyyy-MM-dd、yyyy/MM/dd、yyyyMMdd
 * @param {string} uploadStyle 1、远程上传 2、定时上传
 * @param {string} isCompress true : 压缩上传 false：不压缩，默认压缩上传
 * @param {string} fileName 要上传的日志文件名(含扩展名),如果指定该值,则从日志根目录下寻找名为该值的文件,否则按照默认规则查找日志文件
 * @param {string} ip 当前设备IP地址
 * @param {array} extraLogFiles 表示除了应用程序相关的日志外,额外需要上传的日志文件(可以是一个目录或日志文件路径)
 */
KtLogUploader.prototype.uploadLog = function (
  logDateStr,
  uploadStyle,
  isCompress,
  fileName,
  ip,
  extraLogFiles
) {
  var $this = this;
  return new Promise(function (resolve) {
    //debugger;
    var bufferSize = 1024 * 1024; // 1MB
    var logDate = logDateStr.replace(/[/]/g, '-');
    if (logDate.indexOf('-') == -1) {
      logDate =
        logDate.substr(0, 4) +
        '-' +
        logDate.substr(4, 2) +
        '-' +
        logDate.substr(6, 2);
    }
    var buffer = Buffer.alloc(bufferSize);
    var data;
    var dataIndex = 0;
    var isUploaded = false;
    var uploadStyleStr = '';
    var errorMsg = '';

    if (
      uploadStyle == undefined ||
      uploadStyle == null ||
      isNaN(uploadStyle) ||
      uploadStyle == ''
    ) {
      uploadStyle = 1;
    }
    if (!fileName) {
      fileName = $this.version + '-' + logDate + '.log';
    }
    if (!ip) {
      ip = getIP();
    }
    if (isCompress == undefined || isCompress == null) {
      isCompress = true;
    } else {
      isCompress = (isCompress + '').toString() == 'true';
    }
    if (Object.prototype.toString.call(extraLogFiles) != '[object Array]') {
      extraLogFiles = [];
    }

    var filePath = path.join($this.logRootDir, fileName);
    var zipFileName = fileName;
    var zipFilePath = filePath;
    var appLogs = getLogListByDate(logDate, $this.logRootDir); //应用程序日志文件.
    //包含多个日志文件时必须压缩.
    if (appLogs.length > 1 || extraLogFiles.length > 0) {
      isCompress = true;
    }
    if (isCompress) {
      zipFileName = logDate + '.zip';
      zipFilePath = path.join($this.logRootDir, zipFileName);
      var zip = new AdmZip();
      //打包应用程序的日志文件.
      for (var j = 0; j < appLogs.length; j++) {
        var appLogPath = path.join($this.logRootDir, appLogs[j]);
        if (fs.existsSync(appLogPath)) {
          zip.addLocalFile(appLogPath);
        }
      }
      //打包其他的日志文件.
      for (var i = 0; i < extraLogFiles.length; i++) {
        //路径存在
        if (fs.existsSync(extraLogFiles[i])) {
          var stat = fs.statSync(extraLogFiles[i]);
          if (stat.isDirectory()) {
            zip.addLocalFolder(extraLogFiles[i]);
          } else if (stat.isFile()) {
            zip.addLocalFile(extraLogFiles[i]);
          }
        }
      }
      zip.writeZip(zipFilePath);
    }
    var uploadedCallback = function (fileName, uploadResult, errorMsg, fd) {
      try {
        resolve({
          IsSuccess: uploadResult == 0,
          Data: fileName,
          Message: errorMsg ? errorMsg : '',
        });
      } finally {
        if (fd != null && fd != undefined) {
          fs.close(fd, function (err) {
            deleteLogFile(zipFilePath);
            if (err) {
              console.log('UploadLog-文件流关闭失败:' + err.message);
            }
          });
        } else {
          deleteLogFile(zipFilePath);
        }
      }
    };
    switch (uploadStyle.toString()) {
      case '1':
        uploadStyleStr = '远程上传';
        break;
      case '2':
        uploadStyleStr = '定时上传';
        break;
      default:
        uploadStyleStr = '远程上传';
        break;
    }
    if (!fs.existsSync(zipFilePath)) {
      errorMsg =
        'UploadLog(' +
        uploadStyleStr +
        ')-日志文件【' +
        zipFilePath +
        '】上传失败:文件不存在!';
      console.log(errorMsg);
      uploadedCallback(zipFileName, 1, errorMsg, null);
      return false;
    }
    fs.open(zipFilePath, 'r', function (err, fd) {
      if (err) {
        errorMsg =
          'UploadLog(' +
          uploadStyleStr +
          ')-日志文件【' +
          zipFilePath +
          '】打开失败,错误:' +
          err.message;
        console.log(errorMsg);
        uploadedCallback(zipFileName, 1, errorMsg, fd ? fd : null);
        return;
      }

      function readNextChunk() {
        fs.read(fd, buffer, 0, bufferSize, null, function (err, nread) {
          if (err) {
            errorMsg =
              'UploadLog(' +
              uploadStyleStr +
              ')-日志文件【' +
              filePath +
              '】读取失败,错误:' +
              err.message;
            console.log(errorMsg);
            uploadedCallback(zipFileName, 1, errorMsg, fd ? fd : null);
            return;
          }
          if (nread === 0) {
            if (!isUploaded) {
              uploadedCallback(zipFileName, 0, '', fd);
            }
            return;
          }
          if (nread < bufferSize) data = Buffer.from(buffer.slice(0, nread));
          else data = buffer;

          //上传日志。
          ktHttp.post(
            $this.uploadUrl,
            {
              ip: ip, //设备IP地址
              fileName: zipFileName, //文件名
              fileFlow: data.toString('base64'), //日志Base64内容
              tag: dataIndex.toString(), //首次上传 0，否则 1
            },
            function (data) {
              if (!isNaN(data) && data != '' && data >= 0) {
                dataIndex = 1;
                if (nread < bufferSize) {
                  isUploaded = true;
                  uploadedCallback(zipFileName, 0, '', fd);
                } else {
                  readNextChunk();
                }
              } else {
                errorMsg =
                  'ktHttp-post-日志上传失败(服务端返回:' + data + ')!!!';
                uploadedCallback(zipFileName, 1, errorMsg, fd);
              }
            },
            function (err) {
              errorMsg = 'ktHttp-post-日志上传失败(' + formatJson(err) + ')!!!';
              console.log(errorMsg);
              uploadedCallback(zipFileName, 1, errorMsg, fd);
            }
          );
        });
      }
      readNextChunk();
    });
  }).catch(function (errorMsg) {
    return {
      IsSuccess: false,
      Data: null,
      Message: errorMsg,
    };
  });
};
/**
 * 读取指定日志目录下的所有日志文件名
 */
KtLogUploader.prototype.getLogFileList = function () {
  return getLogList(this.logRootDir);
};
/**
 * 获取指定目录下某一天的所有日志.
 */
KtLogUploader.prototype.getLogListByDate = getLogListByDate;
/**
 * 获取指定日期的日志列表
 * @param {string} dateStr YYYY-MM-DD
 */
function getLogListByDate(dateStr, logDir) {
  var logs = [];
  var logList = getLogList(logDir);
  for (var i = 0; i < logList.length; i++) {
    if (
      logList[i].indexOf(dateStr + '.log') >= 0 ||
      logList[i].indexOf(dateStr.replace(/-/g, '') + '.log') >= 0
    ) {
      logs.push(logList[i]);
    }
  }
  return logs;
}
function getLogList(logDir) {
  if (!fs.existsSync(logDir)) {
    return [];
  }
  var stat = fs.statSync(logDir);
  if (!stat.isDirectory()) {
    return [];
  }
  var files = fs.readdirSync(logDir);
  return files;
}

/**
 * 获取当前系统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;
    }
  }
}
function formatJson(jsonObj) {
  return JSON.stringify(jsonObj, ' ', 4);
}
function subtractDays(date, value) {
  date.setTime(date.getTime() - value * 24 * 60 * 60 * 1000);
  return date;
}
/**
 * 删除指定日志文件
 * @param {*} filePath
 */
function deleteLogFile(filePath) {
  if (fs.existsSync(filePath)) {
    const child_process = require('child_process');
    var stat = fs.statSync(filePath);
    if (stat.isDirectory()) {
      if (process.platform == 'win32') {
        child_process.exec(
          `rd /S /Q ${filePath}`,
          { windowsHide: true },
          function (error, stdOut, stdErr) {
            if (error) {
              console.log(
                '日志文件目录【' +
                  filePath +
                  '】删除失败,错误：' +
                  stdErr +
                  ',' +
                  (error ? error.message : '')
              );
            } else {
              console.log('日志文件目录【' + filePath + '】删除成功');
            }
          }
        );
      } else {
        child_process.exec(`rm -r -f ${filePath}`, {}, function (
          error,
          stdOut,
          stdErr
        ) {
          if (error) {
            console.log(
              '日志文件目录【' +
                filePath +
                '】删除失败,错误：' +
                stdErr +
                ',' +
                (error ? error.message : '')
            );
          } else {
            console.log('日志文件目录【' + filePath + '】删除成功');
          }
        });
      }
      return;
    }
    if (process.platform == 'win32') {
      child_process.exec(`del /Q ${filePath}`, { windowsHide: true }, function (
        error,
        stdOut,
        stdErr
      ) {
        if (error) {
          console.log(
            '日志文件【' +
              filePath +
              '】删除失败,错误：' +
              stdErr +
              ',' +
              (error ? error.message : '')
          );
        } else {
          console.log('日志文件【' + filePath + '】删除成功');
        }
      });
    } else {
      fs.unlink(filePath, (err) => {
        if (err)
          console.log(
            '日志文件【' + filePath + '】删除失败,错误：' + err.message
          );
        else {
          console.log('日志文件【' + filePath + '】删除成功');
        }
      });
    }
  }
}
// export { KtLogUploader }
// export default KtLogUploader;
module.exports = KtLogUploader;
