const deepmerge = require("deepmerge");

/**
 * 判断对象类型
 * @param {*} obj 对象
 */
export function objTypeOf(obj) {
  const toString = Object.prototype.toString;
  const map = {
    "[object Boolean]": "boolean",
    "[object Number]": "number",
    "[object String]": "string",
    "[object Function]": "function",
    "[object Array]": "array",
    "[object Date]": "date",
    "[object RegExp]": "regExp",
    "[object Undefined]": "undefined",
    "[object Null]": "null",
    "[object Object]": "object",
    "[object Blob]": "blob",
  };
  return map[toString.call(obj)];
}

/**
 * 深拷贝
 * @param {Object/Array} data 需要拷贝的数据
 */
export function deepCopy(data, options) {
  const defObj = objTypeOf(data) === "array" ? [] : {};
  return deepmerge(defObj, data, options || {});
}

/**
 * 将目标对象中有的属性值与源对象中的属性值合并
 * @param {Object} target 目标对象
 * @param {Object} sources 源对象
 */
export function objAssign(target, sources) {
  let targ = { ...target };
  for (let k in targ) {
    targ[k] = Object.prototype.hasOwnProperty.call(sources, k)
      ? sources[k]
      : targ[k];
  }
  return targ;
}

/**
 * 文件流下载
 * @param {Object} option 文件下载设置
 */
export function download(option) {
  let defOpt = {
    type: "get",
    url: "",
    data: "",
    fileName: "",
    header: "",
    responseType: "",
  };
  let opt = objAssign(defOpt, option);

  return new Promise((resolve, reject) => {
    let xhr = new XMLHttpRequest();
    xhr.open(opt.type.toUpperCase(), opt.url, true);
    if (opt.responseType) xhr.responseType = opt.responseType;

    // header set
    if (opt.header && objTypeOf(opt.header) === "object") {
      for (let key in opt.header) {
        xhr.setRequestHeader(key, opt.header[key]);
      }
    }

    xhr.onload = function () {
      if (this.readyState === 4 && this.status === 200) {
        resolve(this.response);
      } else {
        reject("请求错误!");
      }
    };

    if (opt.type.toUpperCase() === "POST") {
      let fromData = new FormData();
      for (let key in opt.data) {
        fromData.append(key, opt.data[key]);
      }
      xhr.send(fromData);
    } else {
      xhr.send();
    }
  });
}

/**
 * 构建图表btn
 * @param {Function} h createElement
 * @param {Array} actions 操作分类数组
 */
export function tableAction(h, actions) {
  return actions.map((item) => {
    let attr = {
      props: {
        type: item.type || "primary",
        size: "small",
        disabled: !!item.disabled,
      },
      style: {
        marginRight: "5px",
      },
      on: {
        click: () => {
          item.action();
        },
      },
    };
    return h("el-button", attr, item.name);
  });
}

/**
 * 获取随机code,默认获取16位
 * @param {Number} len 推荐8的倍数
 *
 */
export function randomCode(len = 16) {
  if (len <= 0) return;
  let steps = Math.ceil(len / 8);
  let stepNums = [];
  for (let i = 0; i < steps; i++) {
    let ranNum = Math.random().toString(32).slice(-8);
    stepNums.push(ranNum);
  }

  return stepNums.join("");
}

/**
 * 序列化参数
 * @param {Object} params 参数对象
 */
export function qsParams(params) {
  return Object.entries(params)
    .map((el) => `${el[0]}=${el[1]}`)
    .join("&");
}

/**
 *
 * @param {String} format 时间格式
 * @param {Date} date 需要格式化的时间对象
 */
export function formatDate(format = "YYYY/MM/DD HH:mm:ss", date = new Date()) {
  if (objTypeOf(date) !== "date") return;
  const options = {
    "Y+": date.getFullYear(),
    "M+": date.getMonth() + 1,
    "D+": date.getDate(),
    "H+": date.getHours(),
    "m+": date.getMinutes(),
    "s+": date.getSeconds(),
  };
  Object.entries(options).map(([key, val]) => {
    if (new RegExp("(" + key + ")").test(format)) {
      const zeros = key === "Y+" ? "0000" : "00";
      const value = (zeros + val).substr(("" + val).length);
      format = format.replace(RegExp.$1, value);
    }
  });
  return format;
}

/**
 *  获取时间长度文字
 * @param {Number} timeNumber 时间数值,单位:毫秒
 */
export function timeNumberToText(timeNumber) {
  const DAY_TIME = 24 * 60 * 60 * 1000;
  const HOUR_TIME = 60 * 60 * 1000;
  const MINUTE_TIME = 60 * 1000;
  const SECOND_TIME = 1000;
  let [day, hour, minute, second] = [0, 0, 0, 0];
  let residueTime = timeNumber;

  if (residueTime >= DAY_TIME) {
    day = Math.floor(residueTime / DAY_TIME);
    residueTime -= day * DAY_TIME;
    day += "天";
  }
  if (residueTime >= HOUR_TIME) {
    hour = Math.floor(residueTime / HOUR_TIME);
    residueTime -= hour * HOUR_TIME;
    hour += "小时";
  }
  if (residueTime >= MINUTE_TIME) {
    minute = Math.floor(residueTime / MINUTE_TIME);
    residueTime -= minute * MINUTE_TIME;
    minute += "分钟";
  }
  if (residueTime >= SECOND_TIME) {
    second = Math.round(residueTime / SECOND_TIME);
    second += "秒";
  }

  return [day, hour, minute, second].filter((item) => !!item).join("");
}

/**
 *  警告时间
 * @param {Number} timeNumber 时间数值,单位:毫秒
 * @param {Number} wainingTime 最大剩余警告时间数值,单位:毫秒
 */
export function residueFloorTime(timeNumber, wainingTime = 0) {
  if (timeNumber < 0) {
    return { status: "danger", title: "已过期" };
  }

  const DAY_TIME = 24 * 60 * 60 * 1000;
  const HOUR_TIME = 60 * 60 * 1000;
  const MINUTE_TIME = 60 * 1000;
  const status = timeNumber < wainingTime ? "warning" : "primary";
  let [day, hour, minute] = [0, 0, 0];
  let residueTime = timeNumber;

  if (residueTime >= DAY_TIME) {
    day = Math.floor(residueTime / DAY_TIME);
    residueTime -= day * DAY_TIME;
    return {
      status,
      title: `剩余${day}天`,
    };
  }
  if (residueTime >= HOUR_TIME) {
    hour = Math.floor(residueTime / HOUR_TIME);
    residueTime -= hour * HOUR_TIME;
    return {
      status,
      title: `剩余${hour}小时`,
    };
  }
  if (residueTime >= MINUTE_TIME) {
    minute = Math.floor(residueTime / MINUTE_TIME);
    return {
      status,
      title: `剩余${minute}分钟`,
    };
  }

  return {
    status,
    title: `不足1分钟`,
  };
}

export function parseTimeRangeDateAndTime(startTime, endTime) {
  if (!startTime || !endTime)
    return {
      date: "",
      time: "",
    };

  const st = formatDate("YYYY-MM-DD HH:mm", new Date(startTime)).split(" ");
  const et = formatDate("YYYY-MM-DD HH:mm", new Date(endTime)).split(" ");

  return {
    date: st[0],
    time: `${st[1]}-${et[1]}`,
  };
}

/**
 * 获取本地时间,格式:年月日时分秒
 */
export function localNowDateTime() {
  return formatDate("YYYY年MM月DD日HH时mm分ss秒");
}

/**
 *
 * @param {Number} time 时间戳
 */
export function getTimeDatestamp(time) {
  const date = formatDate("YYYY-MM-DD HH:mm", new Date(time)).split(" ")[0];
  return new Date(`${date} 00:00:00`).getTime();
}

/**
 * 获取指定元素个数的数组
 * @param {Number} num
 */
export function getNumList(num) {
  return "#".repeat(num).split("");
}

/**
 * 清除html标签
 * @param {String} str html字符串
 */
export function removeHtmlTag(str) {
  return str.replace(/<[^>]+>/g, "");
}

/**
 * 计算总数
 * @param {Array} dataList 需要统计的数组
 */
export function calcSum(dataList) {
  if (!dataList.length) return 0;
  return dataList.reduce(function (total, item) {
    return total + item;
  }, 0);
}

/**
 * 计算评卷数
 * @param {Array} dataList 需要统计的数组
 */
export function calcAvg(dataList) {
  if (!dataList.length) return 0;
  return calcSum(dataList) / dataList.length;
}

/** 获取数组最大数 */
export function maxNum(dataList) {
  if (!dataList.length) return 0;
  return Math.max.apply(null, dataList);
}

export function isEmptyObject(obj) {
  return !Object.keys(obj).length;
}

/**
 * 解决后台返回的数据中number位数超过16位的情况
 * @param {String} text json格式字符串
 */
export function jsonBigNumberToString(text) {
  return text
    .replace(/\\":[0-9]{16,19}/g, function (match) {
      return match.slice(0, 3) + '\\"' + match.slice(3) + '\\"';
    })
    .replace(/:[0-9]{16,19}/g, function (match) {
      return match[0] + '"' + match.slice(1) + '"';
    });
}

export function humpToLowLine(a) {
  return a
    .replace(/([A-Z])/g, "-$1")
    .toLowerCase()
    .slice(1);
}

export function pickByNotNull(params) {
  let nData = {};
  Object.entries(params).forEach(([key, val]) => {
    if (val === null || val === "null" || val === "") return;
    nData[key] = val;
  });
  return nData;
}

export function autoSubmitForm(url, params) {
  const form = document.createElement("form");
  form.action = url;
  form.method = "post";

  Object.entries(params).forEach(([key, val]) => {
    const input = document.createElement("input");
    input.type = "hidden";
    input.name = key;
    input.value = val;
    form.appendChild(input);
  });
  document.body.appendChild(form);
  form.submit();
}

export function blobToText(blob) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.readAsText(blob, "utf-8");
    reader.onload = function () {
      resolve(reader.result);
    };
    reader.onerror = function () {
      reject();
    };
  });
}

export function parseHrefParam(urlStr, paramName = null) {
  if (!urlStr) return;
  const url = new URL(urlStr);

  const urlParams = new URLSearchParams(url.search);

  if (paramName) return urlParams.get(paramName);

  let params = {};
  for (const kv of urlParams.entries()) {
    params[kv[0]] = kv[1];
  }
  return params;
}

export function objFilterNull(obj) {
  let nobj = {};
  Object.entries(obj).forEach(([key, val]) => {
    if (val === null || val === "null" || val === "") return;
    nobj[key] = val;
  });
  return nobj;
}