// +---------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者，助力企业发展 ]
// +---------------------------------------------------------------------
// | Copyright (c) 2016~2023 https://www.crmeb.com All rights reserved.
// +---------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件，未经许可不能去掉CRMEB相关版权
// +---------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +---------------------------------------------------------------------

import Cookies from 'js-cookie';
// cookie保存的天数
import { forEach, hasOneOf, objEqual } from '@/libs/tools';
import { cloneDeep } from 'lodash';
const title = '';

// 设置setCookies；
// setToken
export const setCookies = (key, val, cookieExpires) => {
  Cookies.set(key, val, { expires: cookieExpires || 1 });
};
// 获取getCookies；
// getToken
export const getCookies = (key) => {
  return Cookies.get(key);
};

/**
 * 从cookie中移除指定的键值对
 * @param {string} key - 要移除的键名
 * @returns {boolean} - 移除成功返回true，否则返回false
 */
export const removeCookies = (key) => {
  return Cookies.remove(key);
};

/**
 * 判断一个菜单项是否有子菜单
 * @param {object} item - 菜单项对象
 * @returns {boolean} - 有子菜单返回true，否则返回false
 */
export const hasChild = (item) => {
  return item.children && item.children.length !== 0;
};

/**
 * 判断当前用户是否有权限访问该菜单项
 * @param {object} item - 菜单项对象
 * @param {array} access - 用户拥有的权限列表
 * @returns {boolean} - 有权限返回true，否则返回false
 */
const showThisMenuEle = (item, access) => {
  // 判断菜单项是否设置了权限
  if (item.meta && item.meta.access && item.meta.access.length) {
    // 判断用户是否拥有该菜单项的权限
    if (hasOneOf(item.meta.access, access)) return true;
    else return false;
  } else return true;
};

/**
 * @param {Array} list 通过路由列表得到菜单列表
 * @returns {Array}
 */
export const getMenuByRouter = (list, access) => {
  let res = [];
  forEach(list, (item) => {
    if (!item.meta || (item.meta && !item.meta.hideInMenu)) {
      let obj = {
        icon: (item.meta && item.meta.icon) || '',
        name: item.name,
        meta: item.meta,
      };
      if ((hasChild(item) || (item.meta && item.meta.showAlways)) && showThisMenuEle(item, access)) {
        obj.children = getMenuByRouter(item.children, access);
      }
      if (item.meta && item.meta.href) obj.href = item.meta.href;
      if (showThisMenuEle(item, access)) res.push(obj);
    }
  });
  return res;
};

/**
 * @param {Array} routeMetched 当前路由metched
 * @returns {Array}
 */
export const getBreadCrumbList = (route, homeRoute) => {
  let homeItem = {
    ...homeRoute,
  };
  let routeMetched = route.matched;
  if (routeMetched.some((item) => item.name === homeRoute.name)) return [homeItem];
  let res = routeMetched
    .filter((item) => {
      return item.meta === undefined || !item.meta.hideInBread;
    })
    .map((item) => {
      let meta = { ...item.meta };
      if (meta.title && typeof meta.title === 'function') {
        meta.__titleIsFunction__ = true;
        meta.title = meta.title(route);
      }
      let obj = {
        icon: (item.meta && item.meta.icon) || '',
        name: item.name,
        meta: meta,
      };
      return obj;
    });
  res = res.filter((item) => {
    return !item.meta.hideInMenu;
  });
  return [{ ...homeItem, to: homeRoute.path }, ...res];
};

/**
 * 获取处理后的路由标题
 * @param {Object} route - 路由对象
 * @returns {Object} - 处理后的路由对象
 */
export const getRouteTitleHandled = (route) => {
  // 克隆路由对象和元数据对象
  let router = { ...route };
  let meta = { ...route.meta };
  let title = '';
  // 判断元数据对象中是否存在标题属性
  if (meta.title) {
    // 如果标题属性是函数类型，则调用该函数并将结果赋值给title
    if (typeof meta.title === 'function') {
      meta.__titleIsFunction__ = true;
      title = meta.title(router);
    } else title = meta.title;
  }
  // 将处理后的标题赋值给元数据对象中的title属性
  meta.title = title;
  // 将处理后的元数据对象赋值给路由对象中的meta属性
  router.meta = meta;
  // 返回处理后的路由对象
  return router;
};

/**
 * 显示路由标题
 * @param {Object} item - 当前路由对象
 * @param {Object} vm - Vue实例对象
 * @returns {string|undefined} - 返回路由标题字符串或undefined
 */
export const showTitle = (item, vm) => {
  // 从路由元数据中获取标题和标题是否为函数的标志
  let { title, __titleIsFunction__ } = item.meta;
  // 如果没有标题则直接返回
  if (!title) return;
  // 如果标题不存在，则从路由对象中获取名称作为标题
  title = (item.meta && item.meta.title) || item.name;
  // 返回标题字符串
  return title;
};

/**
 * @description 本地存储和获取标签导航列表
 */
export const setTagNavListInLocalstorage = (list) => {
  localStorage.setItem('tagNaveListJavaMer', JSON.stringify(list));
};
/**
 * @returns {Array} 其中的每个元素只包含路由原信息中的name, path, meta三项
 */
export const getTagNavListFromLocalstorage = () => {
  const list = localStorage.getItem('tagNaveListJavaMer');
  return list ? JSON.parse(list) : [];
};

/**
 * @param {Array} routers 路由列表数组
 * @description 用于找到路由列表中name为home的对象
 */
export const getHomeRoute = (routers, homeName = 'home') => {
  let i = -1;
  let len = routers.length;
  let homeRoute = {};
  while (++i < len) {
    let item = routers[i];
    if (item.children && item.children.length) {
      let res = getHomeRoute(item.children, homeName);
      if (res.name) return res;
    } else {
      if (item.name === homeName) homeRoute = item;
    }
  }
  return homeRoute;
};

/**
 * @param {*} list 现有标签导航列表
 * @param {*} newRoute 新添加的路由原信息对象
 * @description 如果该newRoute已经存在则不再添加
 */
export const getNewTagList = (list, newRoute) => {
  const { name, path, meta } = newRoute;
  let newList = [...list];
  if (newList.findIndex((item) => item.path === path) >= 0) return newList;
  else newList.push({ name, path, meta });
  return newList;
};

/**
 * @param {*} access 用户权限数组，如 ['super_admin', 'admin']
 * @param {*} route 路由列表
 */
const hasAccess = (access, route) => {
  if (route.meta && route.meta.access) return hasOneOf(access, route.meta.access);
  else return true;
};

/**
 * 权鉴
 * @param {*} name 即将跳转的路由name
 * @param {*} access 用户权限数组
 * @param {*} routes 路由列表
 * @description 用户是否可跳转到该页
 */
export const canTurnTo = (name, access, routes) => {
  const routePermissionJudge = (list) => {
    return list.some((item) => {
      if (item.children && item.children.length) {
        return routePermissionJudge(item.children);
      } else if (item.name === name) {
        return hasAccess(access, item);
      }
    });
  };

  return routePermissionJudge(routes);
};

/**
 * @param {String} url
 * @description 从URL中解析参数
 */
export const getParams = (url) => {
  const keyValueArr = url.split('?')[1].split('&');
  let paramObj = {};
  keyValueArr.forEach((item) => {
    const keyValue = item.split('=');
    paramObj[keyValue[0]] = keyValue[1];
  });
  return paramObj;
};

/**
 * @param {Array} list 标签列表
 * @param {String} name 当前关闭的标签的name
 */
export const getNextRoute = (list, route) => {
  let res = {};
  if (list.length === 2) {
    res = getHomeRoute(list);
  } else {
    const index = list.findIndex((item) => routeEqual(item, route));
    if (index === list.length - 1) res = list[list.length - 2];
    else res = list[index + 1];
  }
  return res;
};

/**
 * @param {Number} times 回调函数需要执行的次数
 * @param {Function} callback 回调函数
 */
export const doCustomTimes = (times, callback) => {
  let i = -1;
  while (++i < times) {
    callback(i);
  }
};

/**
 * @param {Object} file 从上传组件得到的文件对象
 * @returns {Promise} resolve参数是解析后的二维数组
 * @description 从Csv文件中解析出表格，解析成二维数组
 */
export const getArrayFromFile = (file) => {
  let nameSplit = file.name.split('.');
  let format = nameSplit[nameSplit.length - 1];
  return new Promise((resolve, reject) => {
    let reader = new FileReader();
    reader.readAsText(file); // 以文本格式读取
    let arr = [];
    reader.onload = function (evt) {
      let data = evt.target.result; // 读到的数据
      let pasteData = data.trim();
      arr = pasteData
        .split(/[\n\u0085\u2028\u2029]|\r\n?/g)
        .map((row) => {
          return row.split('\t');
        })
        .map((item) => {
          return item[0].split(',');
        });
      if (format === 'csv') resolve(arr);
      else reject(new Error('[Format Error]:你上传的不是Csv文件'));
    };
  });
};

/**
 * @param {Array} array 表格数据二维数组
 * @returns {Object} { columns, tableData }
 * @description 从二维数组中获取表头和表格数据，将第一行作为表头，用于在表格中展示数据
 */
export const getTableDataFromArray = (array) => {
  let columns = [];
  let tableData = [];
  if (array.length > 1) {
    let titles = array.shift();
    columns = titles.map((item) => {
      return {
        title: item,
        key: item,
      };
    });
    tableData = array.map((item) => {
      let res = {};
      item.forEach((col, i) => {
        res[titles[i]] = col;
      });
      return res;
    });
  }
  return {
    columns,
    tableData,
  };
};

/**
 * 查找元素的上一个指定标签名的父节点
 * @param {Element} ele - 要查找的元素
 * @param {string} tag - 指定的标签名
 * @returns {Element|undefined} - 返回找到的父节点或 undefined
 */
export const findNodeUpper = (ele, tag) => {
  // 如果元素存在父节点
  if (ele.parentNode) {
    // 如果父节点的标签名与指定标签名相同
    if (ele.parentNode.tagName === tag.toUpperCase()) {
      // 返回父节点
      return ele.parentNode;
    } else {
      // 递归查找父节点的父节点
      return findNodeUpper(ele.parentNode, tag);
    }
  }
};

/**
 * 根据类名查找元素的上级节点
 * @param {HTMLElement} ele - 目标元素
 * @param {string[]} classes - 目标类名数组
 * @returns {HTMLElement|null} - 返回符合条件的上级节点，若不存在则返回 null
 */
export const findNodeUpperByClasses = (ele, classes) => {
  // 获取目标元素的父节点
  let parentNode = ele.parentNode;
  if (parentNode) {
    // 获取父节点的类名列表
    let classList = parentNode.classList;
    if (
      // 判断父节点是否存在目标类名
      classList &&
      classes.every((className) => classList.contains(className))
    ) {
      // 返回符合条件的父节点
      return parentNode;
    } else {
      // 递归查找父节点的父节点
      return findNodeUpperByClasses(parentNode, classes);
    }
  }
};

/**
 * 从当前元素向下查找指定标签名的子元素
 * @param {HTMLElement} ele - 当前元素
 * @param {string} tag - 目标标签名
 * @returns {HTMLElement|undefined} - 返回找到的子元素或 undefined
 */
export const findNodeDownward = (ele, tag) => {
  // 将目标标签名转换为大写字母
  const tagName = tag.toUpperCase();
  // 如果当前元素存在子节点
  if (ele.childNodes.length) {
    let i = -1;
    let len = ele.childNodes.length;
    // 遍历子节点
    while (++i < len) {
      let child = ele.childNodes[i];
      // 如果找到目标标签名的子元素，则返回该子元素
      if (child.tagName === tagName) return child;
      // 否则递归查找子元素的子元素
      else return findNodeDownward(child, tag);
    }
  }
};

/**
 * 根据用户权限判断是否可以查看某个页面或操作
 * @param {Array} access - 当前用户的权限数组
 * @param {Array} canViewAccess - 可以查看的权限数组
 * @returns {Boolean} - 是否可以查看
 */
export const showByAccess = (access, canViewAccess) => {
  // 调用 hasOneOf 函数判断当前用户是否有查看权限
  return hasOneOf(canViewAccess, access);
};

/**
 * @description 根据name/params/query判断两个路由对象是否相等
 * @param {*} route1 路由对象
 * @param {*} route2 路由对象
 */
export const routeEqual = (route1, route2) => {
  const params1 = route1.params || {};
  const params2 = route2.params || {};
  const query1 = route1.query || {};
  const query2 = route2.query || {};
  return route1.name === route2.name && objEqual(params1, params2) && objEqual(query1, query2);
};

/**
 * 判断打开的标签列表里是否已存在这个新添加的路由对象
 */
export const routeHasExist = (tagNavList, routeItem) => {
  let len = tagNavList.length;
  let res = false;
  doCustomTimes(len, (index) => {
    if (routeEqual(tagNavList[index], routeItem)) res = true;
  });
  return res;
};

export const localSave = (key, value) => {
  localStorage.setItem(key, value);
};

export const localRead = (key) => {
  return localStorage.getItem(key) || '';
};

// scrollTop animation
export const scrollTop = (el, from = 0, to, duration = 500, endCallback) => {
  if (!window.requestAnimationFrame) {
    window.requestAnimationFrame =
      window.webkitRequestAnimationFrame ||
      window.mozRequestAnimationFrame ||
      window.msRequestAnimationFrame ||
      function (callback) {
        return window.setTimeout(callback, 1000 / 60);
      };
  }
  const difference = Math.abs(from - to);
  const step = Math.ceil((difference / duration) * 50);

  const scroll = (start, end, step) => {
    if (start === end) {
      endCallback && endCallback();
      return;
    }

    let d = start + step > end ? end : start + step;
    if (start > end) {
      d = start - step < end ? end : start - step;
    }

    if (el === window) {
      window.scrollTo(d, d);
    } else {
      el.scrollTop = d;
    }
    window.requestAnimationFrame(() => scroll(d, end, step));
  };
  scroll(from, to, step);
};

/**
 * @description 根据当前跳转的路由设置显示在浏览器标签的title
 * @param {Object} routeItem 路由对象
 * @param {Object} vm Vue实例
 */
export const setTitle = (routeItem, vm) => {
  let winTitle = localStorage.getItem('ADMIN_TITLE') || title;
  const handledRoute = getRouteTitleHandled(routeItem);
  const pageTitle = showTitle(handledRoute, vm);
  const resTitle = pageTitle ? `${winTitle} - ${pageTitle}` : winTitle;
  window.document.title = resTitle;
};

export const R = (menuList, newOpenMenus) => {
  menuList.forEach((item) => {
    let newMenu = {};
    for (let i in item) {
      if (i !== 'children') newMenu[i] = cloneDeep(item[i]);
    }
    newOpenMenus.push(newMenu);
    item.children && R(item.children, newOpenMenus);
  });
  return newOpenMenus;
};

/**
 * 获取当前菜单打开状态
 * @param {Object} to - 当前路由对象
 * @param {Array} menuList - 菜单列表
 * @returns {Array} - 当前菜单打开状态数组
 */
export function getMenuopen(to, menuList) {
  // 初始化所有菜单数组
  const allMenus = [];
  // 遍历菜单列表
  menuList.forEach((menu) => {
    // 转换菜单结构
    const menus = transMenu(menu, []);
    // 添加当前菜单到所有菜单数组
    allMenus.push({
      path: menu.path,
      openNames: [],
    });
    // 添加子菜单到所有菜单数组
    menus.forEach((item) => allMenus.push(item));
  });
  // 查找当前菜单
  const currentMenu = allMenus.find((item) => item.path === to.path);
  // 返回当前菜单打开状态数组
  return currentMenu ? currentMenu.openNames : [];
}

/**
 * 将菜单转换为可展开的形式
 * @param {Object} menu - 菜单对象
 * @param {Array} openNames - 已打开的菜单路径数组
 * @returns {Array} - 可展开的菜单数组
 */
function transMenu(menu, openNames) {
  // 判断当前菜单是否有子菜单
  if (menu.children && menu.children.length) {
    // 将当前菜单路径添加到已打开的菜单路径数组中
    const itemOpenNames = openNames.concat([menu.path]);
    // 递归处理子菜单
    return menu.children.reduce((all, item) => {
      // 将当前子菜单的路径和已打开的菜单路径数组添加到结果数组中
      all.push({
        path: item.path,
        openNames: itemOpenNames,
      });
      // 递归处理子菜单的子菜单
      const foundChildren = transMenu(item, itemOpenNames);
      // 将子菜单的子菜单添加到结果数组中
      return all.concat(foundChildren);
    }, []);
  } else {
    // 如果当前菜单没有子菜单，则直接将当前菜单添加到结果数组中
    return [menu].map((item) => {
      return {
        path: item.path,
        openNames: openNames,
      };
    });
  }
}

export function wss(wsSocketUrl) {
  let ishttps = document.location.protocol == 'https:';
  if (ishttps) {
    return wsSocketUrl.replace('ws:', 'wss:');
  } else {
    return wsSocketUrl.replace('wss:', 'ws:');
  }
}
