import { useGlobSetting } from '/@/hooks/setting';

import { merge, random } from 'lodash-es';

import { isArray } from '/@/utils/is';

import { FormSchema } from '/@/components/Form';

import { reactive } from "vue";

import { getTenantId, getToken } from "/@/utils/auth";

import { useUserStoreWithOut } from "/@/store/modules/user";

import dayjs from 'dayjs';

import Big from 'big.js';



import { Modal } from "ant-design-vue";

import { defHttp } from "@/utils/http/axios";

import { useI18n } from "@/hooks/web/useI18n";



const globSetting = useGlobSetting();

const baseApiUrl = globSetting.domainUrl;

/**

 *  获取文件服务访问路径

 * @param fileUrl 文件路径

 * @param prefix(默认http)  文件路径前缀 http/https

 */

export const getFileAccessHttpUrl = (fileUrl, prefix = 'http') => {

  let result = fileUrl;

  try {

    if (fileUrl && fileUrl.length > 0 && !fileUrl.startsWith(prefix)) {

      //判断是否是数组格式

      let isArray = fileUrl.indexOf('[') != -1;

      if (!isArray) {

        let prefix = `${baseApiUrl}/sys/common/static/`;

        // 判断是否已包含前缀

        if (!fileUrl.startsWith(prefix)) {

          result = `${prefix}${fileUrl}`;

        }

      }

    }

  } catch (err) {}

  return result;

};



/**

 * 触发 window.resize

 */

export function triggerWindowResizeEvent() {

  let event: any = document.createEvent('HTMLEvents');

  event.initEvent('resize', true, true);

  event.eventType = 'message';

  window.dispatchEvent(event);

}



/**

 * 获取随机数

 *  @param length 数字位数

 */

export const getRandom = (length: number = 1) => {

  return '-' + parseInt(String(Math.random() * 10000 + 1), length);

};



/**

 * 随机生成字符串

 * @param length 字符串的长度

 * @param chats 可选字符串区间(只会生成传入的字符串中的字符)

 * @return string 生成的字符串

 */

export function randomString(length: number, chats?: string) {

  if (!length) length = 1;

  if (!chats) {

    // noinspection SpellCheckingInspection

    chats = '0123456789qwertyuioplkjhgfdsazxcvbnm';

  }

  let str = '';

  for (let i = 0; i < length; i++) {

    let num = random(0, chats.length - 1);

    str += chats[num];

  }

  return str;

}



/**

 * 将普通列表数据转化为tree结构

 * @param array tree数据

 * @param opt  配置参数

 * @param startPid 父节点

 */

export const listToTree = (array, opt, startPid) => {

  const obj = {

    primaryKey: opt.primaryKey || 'key',

    parentKey: opt.parentKey || 'parentId',

    titleKey: opt.titleKey || 'title',

    startPid: opt.startPid || '',

    currentDept: opt.currentDept || 0,

    maxDept: opt.maxDept || 100,

    childKey: opt.childKey || 'children',

  };

  if (startPid) {

    obj.startPid = startPid;

  }

  return toTree(array, obj.startPid, obj.currentDept, obj);

};

/**

 *  递归构建tree

 * @param list

 * @param startPid

 * @param currentDept

 * @param opt

 * @returns {Array}

 */

export const toTree = (array, startPid, currentDept, opt) => {

  if (opt.maxDept < currentDept) {

    return [];

  }

  let child = [];

  if (array && array.length > 0) {

    child = array

      .map((item) => {

        // 筛查符合条件的数据(主键 = startPid)

        if (typeof item[opt.parentKey] !== 'undefined' && item[opt.parentKey] === startPid) {

          // 满足条件则递归

          const nextChild = toTree(array, item[opt.primaryKey], currentDept + 1, opt);

          // 节点信息保存

          if (nextChild.length > 0) {

            item['isLeaf'] = false;

            item[opt.childKey] = nextChild;

          } else {

            item['isLeaf'] = true;

          }

          item['title'] = item[opt.titleKey];

          item['label'] = item[opt.titleKey];

          item['key'] = item[opt.primaryKey];

          item['value'] = item[opt.primaryKey];

          return item;

        }

      })

      .filter((item) => {

        return item !== undefined;

      });

  }

  return child;

};



/**

 * 表格底部合计工具方法

 * @param tableData 表格数据

 * @param fieldKeys 要计算合计的列字段

 */

export function mapTableTotalSummary(tableData: Recordable[], fieldKeys: string[]) {

  let totals: any = { _row: '合计', _index: '合计' };

  fieldKeys.forEach((key) => {

    totals[key] = tableData.reduce((prev, next) => {

      // update-begin--author:liaozhiyang---date:20240118---for:【QQYUN-7891】PR 合计工具方法,转换为Nuber类型再计算

      const value = Number(next[key]);

      if (!Number.isNaN(value)) {

        // update-begin--author:liaozhiyang---date:20250224---for:【issues/7830】合计小数计算精度

        prev = Big(prev).plus(value).toString();

        // update-end--author:liaozhiyang---date:20250224---for:【issues/7830】合计小数计算精度

      }

      // update-end--author:liaozhiyang---date:20240118---for:【issues/7830】PR 合计工具方法,转换为Nuber类型再计算

      return prev;

    }, 0);

    // update-begin--author:liaozhiyang---date:20250224---for:【issues/7830】合计小数计算精度

    totals[key] = +totals[key];

    // update-end--author:liaozhiyang---date:20250224---for:【issues/7830】合计小数计算精度

  });

  return totals;

}



/**

 * 简单实现防抖方法

 *

 * 防抖(debounce)函数在第一次触发给定的函数时,不立即执行函数,而是给出一个期限值(delay),比如100ms。

 * 如果100ms内再次执行函数,就重新开始计时,直到计时结束后再真正执行函数。

 * 这样做的好处是如果短时间内大量触发同一事件,只会执行一次函数。

 *

 * @param fn 要防抖的函数

 * @param delay 防抖的毫秒数

 * @returns {Function}

 */

export function simpleDebounce(fn, delay = 100) {

  let timer: any | null = null;

  return function () {

    let args = arguments;

    if (timer) {

      clearTimeout(timer);

    }

    timer = setTimeout(() => {

      // @ts-ignore

      fn.apply(this, args);

    }, delay);

  };

}



/**

 * 日期格式化

 * @param date 日期

 * @param block 格式化字符串

 */

export function dateFormat(date, block) {

  if (!date) {

    return '';

  }

  let format = block || 'yyyy-MM-dd';

  date = new Date(date);

  const map = {

    M: date.getMonth() + 1, // 月份

    d: date.getDate(), // 日

    h: date.getHours(), // 小时

    m: date.getMinutes(), // 分

    s: date.getSeconds(), // 秒

    q: Math.floor((date.getMonth() + 3) / 3), // 季度

    S: date.getMilliseconds(), // 毫秒

  };

  format = format.replace(/([yMdhmsqS])+/g, (all, t) => {

    let v = map[t];

    if (v !== undefined) {

      if (all.length > 1) {

        v = `0${v}`;

        v = v.substr(v.length - 2);

      }

      return v;

    } else if (t === 'y') {

      return date

        .getFullYear()

        .toString()

        .substr(4 - all.length);

    }

    return all;

  });

  return format;

}



/**

 * 获取事件冒泡路径,兼容 IE11,Edge,Chrome,Firefox,Safari

 * 目前使用的地方:JVxeTable Span模式

 */

export function getEventPath(event) {

  let target = event.target;

  let path = (event.composedPath && event.composedPath()) || event.path;



  if (path != null) {

    return path.indexOf(window) < 0 ? path.concat(window) : path;

  }



  if (target === window) {

    return [window];

  }



  let getParents = (node, memo) => {

    const parentNode = node.parentNode;



    if (!parentNode) {

      return memo;

    } else {

      return getParents(parentNode, memo.concat(parentNode));

    }

  };

  return [target].concat(getParents(target, []), window);

}



/**

 * 如果值不存在就 push 进数组,反之不处理

 * @param array 要操作的数据

 * @param value 要添加的值

 * @param key 可空,如果比较的是对象,可能存在地址不一样但值实际上是一样的情况,可以传此字段判断对象中唯一的字段,例如 id。不传则直接比较实际值

 * @returns {boolean} 成功 push 返回 true,不处理返回 false

 */

export function pushIfNotExist(array, value, key?) {

  for (let item of array) {

    if (key && item[key] === value[key]) {

      return false;

    } else if (item === value) {

      return false;

    }

  }

  array.push(value);

  return true;

}

/**

 * 过滤对象中为空的属性

 * @param obj

 * @returns {*}

 */

export function filterObj(obj) {

  if (!(typeof obj == 'object')) {

    return;

  }



  for (let key in obj) {

    if (obj.hasOwnProperty(key) && (obj[key] == null || obj[key] == undefined || obj[key] === '')) {

      delete obj[key];

    }

  }

  return obj;

}



/**

 * 下划线转驼峰

 * @param string

 */

export function underLine2CamelCase(string: string) {

  return string.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());

}



/**

 * 查找树结构

 * @param treeList

 * @param fn 查找方法

 * @param childrenKey

 */

export function findTree(treeList: any[], fn: Fn, childrenKey = 'children') {

  for (let i = 0; i < treeList.length; i++) {

    let item = treeList[i];

    if (fn(item, i, treeList)) {

      return item;

    }

    let children = item[childrenKey];

    if (isArray(children)) {

      let findResult = findTree(children, fn, childrenKey);

      if (findResult) {

        return findResult;

      }

    }

  }

  return null;

}



/** 获取 mapFormSchema 方法 */

export function bindMapFormSchema<T>(spanMap, spanTypeDef: T) {

  return function (s: FormSchema, spanType: T = spanTypeDef) {

    return merge(

      {

        disabledLabelWidth: true,

      } as FormSchema,

      spanMap[spanType],

      s

    );

  };

}



/**

 * 字符串是否为null或null字符串

 * @param str

 * @return {boolean}

 */

export function stringIsNull(str) {

  // 两个 == 可以同时判断 null 和 undefined

  return str == null || str === 'null' || str === 'undefined';

}



/**

 * 【组件多了可能存在性能问题】获取弹窗div,将下拉框、日期等组件挂载到modal上,解决弹窗遮盖问题

 * @param node

 */

export function getAutoScrollContainer(node: HTMLElement) {

  let element: Nullable<HTMLElement> = node

  while (element != null) {

    if (element.classList.contains('scrollbar__view')) {

      // 判断是否有滚动条

      if (element.clientHeight < element.scrollHeight) {

        // 有滚动条时,挂载到父级,解决滚动问题

        return node.parentElement

      } else {

        // 无滚动条时,挂载到body上,解决下拉框遮盖问题

        return document.body

      }

    } else {

      element = element.parentElement

    }

  }

  // 不在弹窗内,走默认逻辑

  return node.parentElement

}



/**

 * 判断子菜单是否全部隐藏

 * @param menuTreeItem

 */

export  function checkChildrenHidden(menuTreeItem){

  //是否是聚合路由

  let alwaysShow=menuTreeItem.alwaysShow;

  if(alwaysShow){

    return false;

  }

  if(!menuTreeItem.children){

    return false

  }

  return menuTreeItem.children?.find((item) => item.hideMenu == false) != null;

}



/**

 * 计算文件大小

 * @param fileSize

 * @param unit

 * @return 返回大小及后缀

 */

export function calculateFileSize(fileSize, unit?) {

  let unitArr = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];

  if (unit && unit.length > 0) {

    unitArr = unit;

  }

  let size = fileSize;

  let unitIndex = 0;

  while (size >= 1024 && unitIndex < unitArr.length - 1) {

    size /= 1024;

    unitIndex++;

  }

  //保留两位小数,四舍五入

  size = Math.round(size * 100) / 100;

  return size + unitArr[unitIndex];

}



/**

 * 获取上传header

 */

export function getHeaders() {

  let tenantId = getTenantId();

  return reactive({

    // 'X-Access-Token': getToken(),

    'Authorization': 'Bearer ' + getToken(),

    // 'X-Tenant-Id': tenantId ? tenantId : '0',

    'tenant_id': tenantId ? tenantId : '0',

  });

}



/** 根据表达式获取相应的用户信息 */

export function getUserInfoByExpression(expression) {

  if (!expression) {

    return expression;

  }

  // 当前日期

  if (expression === 'sys_date' || expression === 'sysDate') {

    return dayjs().format('YYYY-MM-DD');

  }

  // 当前时间

  if (expression === 'sys_time' || expression === 'sysTime') {

    return dayjs().format('HH:mm:ss');

  }

  const userStore = useUserStoreWithOut();

  let userInfo = userStore.getUserInfo;

  if (userInfo) {

    switch (expression) {

      case 'sysUserId':

        return userInfo.id;

      // 当前登录用户登录账号

      case 'sysUserCode':

      case 'sys_user_code':

        return userInfo.username;

      // 当前登录用户真实名称

      case 'sysUserName':

        return userInfo.realname;

      // 当前登录用户部门编号

      case 'sysOrgCode':

      case 'sys_org_code':

        return userInfo.orgCode;

    }

  }

  return expression;

}



/**

 * 替换表达式(#{xxx})为用户信息

 * @param expression

 */

export function replaceUserInfoByExpression(expression: string | any[]) {

  if (!expression) {

    return expression;

  }

  const isString = typeof expression === 'string';

  const isArray = Array.isArray(expression)

  if (!isString && !isArray) {

    return expression;

  }

  const reg = /#{(.*?)}/g;

  const replace = (str) => {

    if (typeof str !== 'string') {

      return str;

    }

    let result = str.match(reg);

    if (result && result.length > 0) {

      result.forEach((item) => {

        let userInfo = getUserInfoByExpression(item.substring(2, item.length - 1));

        str = str.replace(item, userInfo);

      });

    }

    return str;

  };

  // @ts-ignore

  return isString ? replace(expression) : expression.map(replace);

}



/**

 * 设置租户缓存,当租户退出的时候

 * 

 * @param tenantId

 */

export async function userExitChangeLoginTenantId(tenantId){

  const userStore = useUserStoreWithOut();

  //step 1 获取用户租户

  const url = '/sys/tenant/getCurrentUserTenant'

  let currentTenantId = null;

  const data = await defHttp.get({ url });

  if(data && data.list){

    let arr = data.list;

    if(arr.length>0){

      //step 2.判断当前id是否存在用户租户中

      let filterTenantId = arr.filter((item) => item.id == tenantId);

      //存在说明不是退出的不是当前租户,还用用来的租户即可

      if(filterTenantId && filterTenantId.length>0){

        currentTenantId = tenantId;

      }else{

        //不存在默认第一个

        currentTenantId = arr[0].id

      }

    }

  }

  let loginTenantId = getTenantId();

  userStore.setTenant(currentTenantId);



  //update-begin---author:wangshuai---date:2023-11-07---for:【QQYUN-7005】退租户,判断退出的租户ID与当前租户ID一致,再刷新---

  //租户为空,说明没有租户了,需要刷新页面。或者当前租户和退出的租户一致则需要刷新浏览器

  if(!currentTenantId || tenantId == loginTenantId){

    window.location.reload();

  }

  //update-end---author:wangshuai---date:2023-11-07---for:【QQYUN-7005】退租户,判断退出的租户ID与当前租户ID一致,再刷新---

}



/**

 * 我的租户模块需要开启多租户提示

 * 

 * @param title 标题

 */

export function tenantSaasMessage(title){

  let tenantId = getTenantId();

  if(!tenantId){

    Modal.confirm({

      title:title,

      content: '此菜单需要在多租户模式下使用,否则数据会出现混乱',

      okText: '确认',

      okType: 'danger',

      // @ts-ignore

      cancelButtonProps: { style: { display: 'none' } },

    })

  }

}



/**

 * 判断日期和当前时间是否为同一天

 * @param dateStr

 */

export function sameDay(dateStr) {

  if (!dateStr) {

    return false;

  }

  // 获取当前日期

  let currentDate = new Date();

  let currentDay = currentDate.getDate();

  let currentMonth = currentDate.getMonth();

  let currentYear = currentDate.getFullYear();



  //创建另一个日期进行比较

  let otherDate = new Date(dateStr);

  let otherDay = otherDate.getDate();

  let otherMonth = otherDate.getMonth();

  let otherYear = otherDate.getFullYear();



  //比较日期

  if (currentDay === otherDay && currentMonth === otherMonth && currentYear === otherYear) {

    return true;

  } else {

    return false;

  }

}





/**

 * 翻译菜单名称

 * 2024-02-28

 * liaozhiyang

 * @param data

 */

export function translateTitle(data) {

  if (data?.length) {

    const { t } = useI18n();

    data.forEach((item) => {

      if (item.slotTitle) {

        if (item.slotTitle.includes("t('") && t) {

          item.slotTitle = new Function('t', `return ${item.slotTitle}`)(t);

        }

      }

      if (item.children?.length) {

        translateTitle(item.children);

      }

    });

  }

  return data;

}



/**

 *

 * 深度冻结对象

 * @param obj Object or Array

 */

export function freezeDeep(obj: Recordable | Recordable[]) {

  if (obj != null) {

    if (Array.isArray(obj)) {

      obj.forEach(item => freezeDeep(item))

    } else if (typeof obj === 'object') {

      Object.values(obj).forEach(value => {

        freezeDeep(value)

      })

    }

    Object.freeze(obj)

  }

  return obj

}