import Cookies from "js-cookie";

/**
 * Parse the time to string
 * @param {(Object|string|number)} time
 * @param {string} cFormat
 * @returns {string | null}
 */
export function parseTime(time, cFormat) {
  if (arguments.length === 0 || !time) {
    return null;
  }
  const format = cFormat || "{y}-{m}-{d} {h}:{i}:{s}";
  let date;
  if (typeof time === "object") {
    date = time;
  } else {
    if (typeof time === "string") {
      if (/^[0-9]+$/.test(time)) {
        // support "1548221490638"
        // eslint-disable-next-line
        time = parseInt(time);
      } else {
        // support safari
        // https://stackoverflow.com/questions/4310953/invalid-date-in-safari
        // eslint-disable-next-line
        time = time.replace(new RegExp(/-/gm), "/");
      }
    }

    if (typeof time === "number" && time.toString().length === 10) {
      // eslint-disable-next-line
      time *= 1000;
    }
    date = new Date(time);
  }
  const formatObj = {
    y: date.getFullYear(),
    m: date.getMonth() + 1,
    d: date.getDate(),
    h: date.getHours(),
    i: date.getMinutes(),
    s: date.getSeconds(),
    a: date.getDay(),
  };
  const timeStr = format.replace(/{([ymdhisa])+}/g, (result, key) => {
    const value = formatObj[key];
    // Note: getDay() returns 0 on Sunday
    if (key === "a") {
      return ["日", "一", "二", "三", "四", "五", "六"][value];
    }
    return value.toString().padStart(2, "0");
  });
  return timeStr;
}

/**
 * @param {number} time
 * @param {string} option
 * @returns {string}
 */
export function formatTime(time, option) {
  if (`${time}`.length === 10) {
    // eslint-disable-next-line
    time = parseInt(time) * 1000;
  } else {
    // eslint-disable-next-line
    time = +time;
  }
  const d = new Date(time);
  const now = Date.now();

  const diff = (now - d) / 1000;

  if (diff < 30) {
    return "刚刚";
  }
  if (diff < 3600) {
    // less 1 hour
    return `${Math.ceil(diff / 60)}分钟前`;
  }
  if (diff < 3600 * 24) {
    return `${Math.ceil(diff / 3600)}小时前`;
  }
  if (diff < 3600 * 24 * 2) {
    return "1天前";
  }
  if (option) {
    return parseTime(time, option);
  }
  return `${
    d.getMonth() + 1
  }月${d.getDate()}日${d.getHours()}时${d.getMinutes()}分`;
}

/**
 * @param {string} url
 * @returns {Object}
 */
export function getQueryObject(url) {
  // eslint-disable-next-line
  url = url == null ? window.location.href : url;
  const search = url.substring(url.lastIndexOf("?") + 1);
  const obj = {};
  const reg = /([^?&=]+)=([^?&=]*)/g;
  search.replace(reg, (rs, $1, $2) => {
    const name = decodeURIComponent($1);
    let val = decodeURIComponent($2);
    val = String(val);
    obj[name] = val;
    return rs;
  });
  return obj;
}

/**
 * @param {string} input value
 * @returns {number} output value
 */
export function byteLength(str) {
  // returns the byte length of an utf8 string
  let s = str.length;
  // eslint-disable-next-line
  for (let i = str.length - 1; i >= 0; i--) {
    const code = str.charCodeAt(i);
    // eslint-disable-next-line
    if (code > 0x7f && code <= 0x7ff) s++;
    // eslint-disable-next-line
    else if (code > 0x7ff && code <= 0xffff) s += 2;
    // eslint-disable-next-line
    if (code >= 0xdc00 && code <= 0xdfff) i--;
  }
  return s;
}

/**
 * @param {Array} actual
 * @returns {Array}
 */
export function cleanArray(actual) {
  const newArray = [];
  // eslint-disable-next-line
  for (let i = 0; i < actual.length; i++) {
    if (actual[i]) {
      newArray.push(actual[i]);
    }
  }
  return newArray;
}

/**
 * @param {Object} json
 * @returns {Array}
 */
export function param(json) {
  if (!json) return "";
  return cleanArray(
    Object.keys(json).map((key) => {
      if (json[key] === undefined) return "";
      return `${encodeURIComponent(key)}=${encodeURIComponent(json[key])}`;
    })
  ).join("&");
}

/**
 * @param {string} url
 * @returns {Object}
 */
export function param2Obj(url) {
  const search = decodeURIComponent(url.split("?")[1]).replace(/\+/g, " ");
  if (!search) {
    return {};
  }
  const obj = {};
  const searchArr = search.split("&");
  searchArr.forEach((v) => {
    const index = v.indexOf("=");
    if (index !== -1) {
      const name = v.substring(0, index);
      const val = v.substring(index + 1, v.length);
      obj[name] = val;
    }
  });
  return obj;
}

/**
 * @param {string} val
 * @returns {string}
 */
export function html2Text(val) {
  const div = document.createElement("div");
  div.innerHTML = val;
  return div.textContent || div.textContent;
}

/**
 * Merges two objects, giving the last one precedence
 * @param {Object} target
 * @param {(Object|Array)} source
 * @returns {Object}
 */
export function objectMerge(target, source) {
  if (typeof target !== "object") {
    // eslint-disable-next-line
    target = {};
  }
  if (Array.isArray(source)) {
    return source.slice();
  }
  Object.keys(source).forEach((property) => {
    const sourceProperty = source[property];
    if (typeof sourceProperty === "object") {
      // eslint-disable-next-line
      target[property] = objectMerge(target[property], sourceProperty);
    } else {
      // eslint-disable-next-line
      target[property] = sourceProperty;
    }
  });
  return target;
}

/**
 * @param {HTMLElement} element
 * @param {string} className
 */
export function toggleClass(element, className) {
  if (!element || !className) {
    return;
  }
  let classString = element.className;
  const nameIndex = classString.indexOf(className);
  if (nameIndex === -1) {
    classString += `${className}`;
  } else {
    classString =
      classString.substr(0, nameIndex) +
      classString.substr(nameIndex + className.length);
  }
  // eslint-disable-next-line
  element.className = classString;
}

/**
 * @param {string} type
 * @returns {Date}
 */
export function getTime(type) {
  if (type === "start") {
    return new Date().getTime() - 3600 * 1000 * 24 * 90;
  }
  return new Date(new Date().toDateString());
}

/**
 * @param {Function} func
 * @param {number} wait
 * @param {boolean} immediate
 * @return {*}
 */
export function debounce(func, wait, immediate) {
  let timeout, args, context, timestamp, result;

  const later = function () {
    // 据上一次触发时间间隔
    const last = +new Date() - timestamp;

    // 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait
    if (last < wait && last > 0) {
      timeout = setTimeout(later, wait - last);
    } else {
      timeout = null;
      // 如果设定为immediate===true，因为开始边界已经调用过了此处无需调用
      if (!immediate) {
        result = func.apply(context, args);
        // eslint-disable-next-line
        if (!timeout) context = args = null;
      }
    }
  };
  // eslint-disable-next-line
  return function (...args) {
    // eslint-disable-next-line @typescript-eslint/no-this-alias
    context = this;
    timestamp = +new Date();
    const callNow = immediate && !timeout;
    // 如果延时不存在，重新设定延时
    if (!timeout) timeout = setTimeout(later, wait);
    if (callNow) {
      result = func.apply(context, args);
      // eslint-disable-next-line
      context = args = null;
    }

    return result;
  };
}

/**
 * This is just a simple version of deep copy
 * Has a lot of edge cases bug
 * If you want to use a perfect deep copy, use lodash's _.cloneDeep
 * @param {Object} source
 * @returns {Object}
 */
export function deepClone(source) {
  if (!source && typeof source !== "object") {
    throw new Error("error arguments", "deepClone");
  }
  const targetObj = source.constructor === Array ? [] : {};
  Object.keys(source).forEach((keys) => {
    if (source[keys] && typeof source[keys] === "object") {
      targetObj[keys] = deepClone(source[keys]);
    } else {
      targetObj[keys] = source[keys];
    }
  });
  return targetObj;
}

/**
 * @param {Array} arr
 * @returns {Array}
 */
export function uniqueArr(arr) {
  return Array.from(new Set(arr));
}

/**
 * @returns {string}
 */
export function createUniqueString() {
  const timestamp = `${+new Date()}`;
  // eslint-disable-next-line
  const randomNum = `${parseInt((1 + Math.random()) * 65536)}`;
  return (+(randomNum + timestamp)).toString(32);
}

/**
 * Check if an element has a class
 * @param {HTMLElement} elm
 * @param {string} cls
 * @returns {boolean}
 */
export function hasClass(ele, cls) {
  return !!ele.className.match(new RegExp(`(\\s|^)${cls}(\\s|$)`));
}

/**
 * Add class to element
 * @param {HTMLElement} elm
 * @param {string} cls
 */
export function addClass(ele, cls) {
  // eslint-disable-next-line
  if (!hasClass(ele, cls)) ele.className += ` ${cls}`;
}

/**
 * Remove class from element
 * @param {HTMLElement} elm
 * @param {string} cls
 */
export function removeClass(ele, cls) {
  if (hasClass(ele, cls)) {
    const reg = new RegExp(`(\\s|^)${cls}(\\s|$)`);
    // eslint-disable-next-line
    ele.className = ele.className.replace(reg, " ");
  }
}

/**
 * 导出 excel
 * @param {*} data 要导出的数据
 * @param {*} fileName 文件名
 */
export function exportExcel(data, fileName) {
  const blob = new Blob([data], {
    type: "application/vnd.ms-excel",
  });
  if ("download" in document.createElement("a")) {
    // 非IE下载
    const elink = document.createElement("a");
    elink.download = fileName;
    elink.style.display = "none";
    elink.href = URL.createObjectURL(blob);
    document.body.appendChild(elink);
    elink.click();
    URL.revokeObjectURL(elink.href); // 释放URL 对象
    document.body.removeChild(elink);
  } else {
    // IE10+下载
    navigator.msSaveBlob(blob, fileName);
  }
}

/**
 * 生成uuid
 */
export function uuid() {
  function S4() {
    // eslint-disable-next-line
    return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
  }
  return `${S4() + S4()}_${S4()}_${S4()}_${S4()}_${S4()}${S4()}${S4()}`;
}

/**
 * 获取主域名
 */
// eslint-disable-next-line
export const getDomain = () => {
  let hostname;
  if (window.location.href) {
    hostname = new URL(window.location.href).hostname;
    const domainType = checkIpOrDomain(hostname);
    if (domainType === "domain") {
      const tempArr = hostname.split(".");
      return `${tempArr[1]}.${tempArr[2]}`;
    }
    return hostname;
  }
};

export const clearAllCookies = () => {
  // 清除localStorage, 只清除cookie信息
  // window.localStorage.clear()
  // window.sessionStorage.clear()
  // 清除所有Cookies数据
  const JsonCookies = Cookies.getJSON();
  Object.keys(JsonCookies).forEach((key) => {
    Cookies.remove(key, { domain: getDomain() });
  });
};
// eslint-disable-next-line
function checkIpOrDomain(value) {
  const ipReg =
    /^(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])$/;
  const domainReg =
    /^([\w-]+\.)+((com)|(net)|(org)|(gov\.cn)|(info)|(cc)|(com\.cn)|(net\.cn)|(org\.cn)|(name)|(biz)|(tv)|(cn)|(mobi)|(name)|(sh)|(ac)| {3}(io)|(tw)|(com\.tw)|(hk)|(com\.hk)|(ws)|(travel)|(us)|(tm)|(la)|(me\.uk)|(org\.uk)|(ltd\.uk)|(plc\.uk)|(in)|(eu)|(it)|(jp))$/;
  if (value) {
    if (ipReg.test(value)) {
      return "ip";
    }
    if (domainReg.test(value)) {
      return "domain";
    }
  }
}

// 数组去重
export function arrayDuplicateRemoval(array, property) {
  const tempArray = [];
  // eslint-disable-next-line
  const hasObj = new Object();
  if (array.length > 0) {
    if (typeof array[1] === "object") {
      // eslint-disable-next-line
      for (let i = 0; i < array.length; i++) {
        if (!hasObj[array[i][property]]) {
          hasObj[array[i][property]] = 1;
          tempArray.push(array[i]);
        }
      }
    } else {
      // eslint-disable-next-line
      for (let i = 0; i < array.length; i++) {
        if (!tempArray.includes(array[i])) {
          tempArray.push(array[i]);
        }
      }
    }
    return tempArray;
  }
  return array;
}

export const computeKeepAliveComponents = (vm, cacheKeepAliveComponents) => {
  /* eslint-disable */
  // Check sub page use the layout
  const curRoutePath = vm.$route.path;
  const _Matched = vm.$route.matched.filter(
    (route) => route.path === curRoutePath
  );

  // check match component
  if (_Matched?.length > 0) {
    const {
      components: { default: defaultComponent },
      instances: { default: defaultInstance },
    } = _Matched[0];
    const { options } = defaultComponent;
    // 需要查看 https://github.com/vuejs/vue-loader/commit/001382dad684b409082b7196b40a5c52a3a3169e
    // vue-loader: exposeFilename 选项要设置成true, 才会有 options?.__file
    // Dev：optionsComponentName || __file
    // Product: name
    const keyName = options?.name || options?.__file || defaultComponent?.name;

    const selfName = vm.$options.name || vm.$options.__file || "";
    if (keyName && selfName !== keyName) {
      const isEnableKeppAlive = vm.$route.meta?.keepAlive === 1;
      cacheKeepAliveComponents[keyName] = isEnableKeppAlive;
    }
  }

  // Note: must Add self' component name in cacheKeepAliveComponents

  const cache = checkSelfForKeepAliveCache(
    vm,
    Object.keys(cacheKeepAliveComponents).filter(
      (name) => cacheKeepAliveComponents[name] === true
    ),
    cacheKeepAliveComponents
  );
  // Out the final alive components
  const aliveComponents = Object.keys(cache).filter(
    (name) => cache[name] === true
  );
  return aliveComponents;
  /* eslint-enable */
};
