/**
 * 
 * @param str 字符串
 * @param caseSensitive 是否小大写敏感
 * @returns 返回哈希值
 */

import BigNumber from "bignumber.js";
import { isNil } from "lodash";
import { Condition } from "../components/table/SecondFilter/types";
import { getMediaIcon, isImg } from "../renderers/Lion/utils/utils";
import { isMobile } from "./helper";
import { Shell } from "./shell";
import { tools } from "./shell/tools";
import { evalExpression } from "./tpl";
import { tokenize } from "./tpl-builtin";



// type ScanAfterPort = IExpress

//字符串哈希函数
export function getHashCode(str: string = '', caseSensitive?: boolean) {
  if (!caseSensitive) {
    str = str.toLowerCase();
  }
  var hash = 1315423911, i, ch;
  for (i = str.length - 1; i >= 0; i--) {
    ch = str.charCodeAt(i);
    hash ^= ((hash << 5) + ch + (hash >> 2));
  }

  return (hash & 0x7FFFFFFF);
}
/**
 * 
 * @param array 数据
 * @param key 主键
 * @returns boolean，是否重复
 */
export const checkDuplicateKeys = (array: obj[], key: string) => {
  const keySet = new Set();
  for (let i = 0; i < array.length; i++) {
    const item = array[i];
    const keyValue = item[key];
    if (keySet.has(keyValue)) {
      // 重复主键
      return true;
    }
    keySet.add(keyValue);
  }
  // 没有重复主键
  return false;
};

enum JumpTarget {
  INCLINENT = 1, // 系统内部打开新应用
  NEWWIN = 4, // 打开外部窗口
}
// 判断是否可以跳转
export const linkJump = (linkId: string, data: any, dataDisabeExpress?: string) => {
  if (!linkId) return false
  const isVar = /\$\{.*?\}/g.test(linkId)
  const expressResValid = !dataDisabeExpress || !evalExpression(dataDisabeExpress || '', data)
  if (isVar) {
    const startIdx = linkId.indexOf('{') + 1
    const endIdx = linkId.indexOf('}')
    const fieldName = linkId.substring(startIdx, endIdx)
    return data[fieldName] != undefined && expressResValid
  } else return expressResValid

}
// 判断跳转的方法tab/弹窗
export function ModleHandleClick(props: any, tbth?: any) {
  const { linkUrl, linkSize, linkType, data, env, handleJump, linkTitle, linkId, matrixId, classnames: cx, } = props
  if (linkUrl && !isNil(props.value)) {
    const drawer = tbth?.closest(`.${cx('Drawer')}`)
    const title = tokenize(linkTitle, data)
    if(linkType == JumpTarget.INCLINENT && !env.onPageLink) {
      sessionStorage.setItem('envDataStr', JSON.stringify(env))
    }
    const url = tokenize(linkUrl, data)
    if (((isMobile() && matrixId && !drawer) || linkType == JumpTarget.INCLINENT || linkType == "1") && env.onPageLink) {
      const pageId = tokenize(linkId, data)
      const id = getHashCode(url).toString();
      env.onPageLink(id, pageId, title ?? 'title', url, data, true)
      // 直接跳转外部页面

    } else if (linkType == JumpTarget.NEWWIN) {
      const pageUrl = tokenize(linkId, data, '| url_decode')
      window.open(pageUrl, '__blank')
    } else {
      const { redirectRouter, redirectType, redirectApp } = env.parseLinkUrl?.(url)
      handleJump?.({
        linkUrl: redirectRouter,
        linkSize: linkSize,
        linkTitle: title,
        bodydata: data,
        linkAppId: redirectApp,
        redirectType
      })
    }
  }
}

export function handlelimitSize(max?: number, min?: number, body?: any, showModal?: (val: string) => void) {
  if (max !== undefined && min !== undefined) {
    if (min > max) {
      showModal?.('最小值不得大于最大值')
      return false
    }
    if (body.length < min) {
      showModal?.(`最少添加${min}个`)
      return false
    } else if (body.length > max) {
      showModal?.(`最多添加${max}个`)
      return false
    }
  }
  if (max !== undefined && min == undefined && body.length > max) {
    showModal?.(`最多添加${max}个`)
    return false
  }
  if (max == undefined && min !== undefined && body.length < min) {
    showModal?.(`最少添加${min}个`)
    return false
  }
  return true
}

export function dealBigMoney(n: number) {
  const fraction = ['角', '分'];
  const digit = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'];
  const unit = [['元', '万', '亿'], ['', '拾', '佰', '仟']];
  const head = n < 0 ? '欠' : '';
  n = Math.abs(n);
  let s = '';
  for (var i = 0; i < fraction.length; i++) {
    s += (digit[Math.floor(n * 10 * Math.pow(10, i)) % 10] + fraction[i]).replace(/零./, '');
  }
  s = s || '整';
  n = Math.floor(n);
  for (let i = 0; i < unit[0].length && n > 0; i++) {
    let p = '';
    for (var j = 0; j < unit[1].length && n > 0; j++) {
      p = digit[n % 10] + unit[1][j] + p; n = Math.floor(n / 10);
    }
    s = p.replace(/(零.)*零$/, '').replace(/^$/, '零') + unit[0][i] + s;
  }
  return head + s.replace(/(零.)*零元/, '元').replace(/(零.)+/g, '零').replace(/^整$/, '零元整');
}

export function dealBigNumber(n: number) {
  if (n === 0) return '零'
  let num = Math.abs(n)
  const numArr = new Array("零", "一", "二", "三", "四", "五", "六", "七", "八", "九", "十");
  const unitArr = new Array("", "十", "百", "千", "万", "亿", "点", "");
  let a = ("" + num).replace(/(^0*)/g, "").split("."), k = 0, re = "";
  for (let i = a[0].length - 1; i >= 0; i--) {
    switch (k) {
      case 0:
        re = unitArr[7] + re;
        break;
      case 4:
        if (!new RegExp("0{4}//d{" + (a[0].length - i - 1) + "}$")
          .test(a[0]))
          re = unitArr[4] + re;
        break;
      case 8:
        re = unitArr[5] + re;
        unitArr[7] = unitArr[5];
        k = 0;
        break;
    }
    if (k % 4 == 2 && a[0].charAt(i + 2) != '0' && a[0].charAt(i + 1) == '0') {
      re = numArr[0] + re;
    }
    if (a[0].charAt(i) != '0') {
      re = numArr[a[0].charAt(i)] + unitArr[k % 4] + re;
    }
    k++;
  }
  if (a.length > 1) {
    re += unitArr[6];
    for (var i = 0; i < a[1].length; i++)
      re += numArr[a[1].charAt(i)];
  }
  if (re == '一十') re = "十";
  if (re.match(/^一/) && re.length == 3) re = re.replace("一", "");
  return (n < 0 ? '负' : '') + re;
}

/**
 * 
 * @param value 数值
 * @param showUppercase 转换类型
 * @returns 转换后的值
 */
export function translateNumber(value: any, showUppercase: 0 | 1 | 2) {
  if (showUppercase === 1) {
    value = dealBigNumber(Number(+value))
  } else if (showUppercase === 2) {
    value = dealBigMoney(Number(+value))
  }
  return value
}

export function calcFn(formula: 'sum' | 'avg' | 'max' | 'min' | 'count' | string, fieldName: string, items: any[]): number {
  if (!Array.isArray(items)) return 0
  const tmpItems = items.filter(item => item[fieldName] != undefined)
  switch (formula) {
    case 'sum':
      return tmpItems.reduce((previous, current) => new BigNumber(previous).plus(Number(current[fieldName]) || 0).toNumber(), 0)
    case 'avg':
      const sum = tmpItems.reduce((previous, current) => new BigNumber(previous).plus(Number(current[fieldName]) || 0), 0)
      const count = items.length
      return new BigNumber(sum).dividedBy(count).toNumber()
    case 'max':
      return tmpItems.reduce((previous, current) => Math.max(previous, Number(current[fieldName]) || 0), Number.MIN_VALUE)
    case 'min':
      return tmpItems.length ? tmpItems.reduce((previous, current) => Math.min(previous, Number(current[fieldName]) || 0), Number.MAX_VALUE) : 0
    case 'count':
      return tmpItems.length
    default:
      if (formula.includes('+') || formula.includes('-') || formula.includes('*') || formula.includes('/') || formula.includes('(') || formula.includes(')')) {
        return deepCalcFn(formula, items)
      }
      return 0
  }
}
export function deepCalcFn(formula: string, items: any[]) {
  let str = formula
  let fns = str.match(/(AVG|SUM|MAX|MIN|COUNT)/g);
  let params = str.match(/\((.*?)\)/g)!.map(param => param.replace('(', '').replace(')', ''));
  if (fns && items.length > 0) {
    let calculatedStr = '';

    fns.forEach((fn, index) => {
      if (index === 0) {
        calculatedStr += calcFn(fn.toLocaleLowerCase(), params[index], items);
      } else {
        let operator = str.match(/(\*|\+|\-|\/)/g)![index - 1];
        calculatedStr += `${operator}${calcFn(fn.toLocaleLowerCase(), params[index], items)}`
      }
    });
    let res;
    try {
      res = eval(calculatedStr)
    } catch (error) {
      res = 0;
    }
    return res
  }


  return 0
}


export function sortFn(a: any, b: any, sortBy?: 'asc' | 'desc') {
  if (sortBy == undefined) return 0
  if (typeof a === 'number' && typeof b === 'number') {
    return sortBy === 'asc' ? a - b : b - a;
  }
  return sortBy === 'asc'
    ? String(a ?? '').localeCompare(String(b ?? ''), undefined, { numeric: true, ignorePunctuation: false })
    : String(b ?? '').localeCompare(String(a ?? ''), undefined, { numeric: true, ignorePunctuation: false })
}

export function filterFn(items: any[], columnName: string, condition: Condition, _value1?: string | number, _value2?: string | number, caseSensitive = true) {
  return items.filter((item: any) => {

    // 如果转不动数字保持原来的值
    let value = item[columnName]
    let value1 = _value1
    let value2 = _value2
    // 需要才转数字 分别是 大于 小于 等于 大于等于 小于等于
    const tryToTransValueToNumber = () => {
      // 如果转不成数字就按原值处理
      if (!isNil(value) && !isNaN(+value)) {
        value = +value
        if (!isNil(_value1) && !isNaN(+_value1)) { value1 = +_value1 }
        if (!isNil(_value2) && !isNaN(+_value2)) { value2 = +_value2 }
      }
    }

    const valueToUpperCase = () => {
      if (!caseSensitive) {
        if (typeof value1 == 'string') value1 = value1.toUpperCase()
        if (typeof value == 'string') value = value.toUpperCase()
      }
    }

    const tryParseExpr = () => {
      if (typeof value1 == 'string') {
        const fields = value1.match(/\[(.*?)\]/g)
        if (fields) {
          for (const field of fields) {
            const fieldValue = item[field.slice(1, field.length - 1)]
            //typeof fieldValue == 'number' ? `${fieldValue}` : `'${fieldValue}'`
            value1 = value1.replaceAll(field, String(fieldValue))
          }
          try {
            value1 = eval(value1.replaceAll('||', '+'))
          } catch { }
        }
      }
    }

    switch (condition) {
      case Condition.GreaterThan:
        tryToTransValueToNumber()
        tryParseExpr()
        return value != null && (value) > (value1!)
      case Condition.LessThan:
        tryToTransValueToNumber()
        tryParseExpr()
        return value != null && (value) < (value1!)
      case Condition.Between:
        tryToTransValueToNumber()
        tryParseExpr()
        return (value) >= (value1!) && (value) <= (value2!)
      case Condition.Equal:
        valueToUpperCase()
        if (typeof value1 == 'string') {
          if (value1.includes(',')) {
            return value1.split(',').some(v => value == v)
          } else if (value1.includes('，')) {
            return value1.split('，').some(v => value == v)
          }
          tryParseExpr()
        }
        return value == value1
      case Condition.NotEqual:
        valueToUpperCase()
        if (typeof value1 == 'string') {
          if (value1.includes(',')) {
            return value1.split(',').every(v => value != v)
          } else if (value1.includes('，')) {
            return value1.split('，').every(v => value != v)
          }
          tryParseExpr()
        }
        return value != value1
      case Condition.GreaterThanOrEqual:
        tryToTransValueToNumber()
        tryParseExpr()
        return value != null && (value) >= (value1!)
      case Condition.LessThanOrEqual:
        tryToTransValueToNumber()
        tryParseExpr()
        return value != null && (value) <= (value1!)
      case Condition.Null:
        return value == null
      case Condition.NotNull:
        return value != null
      case Condition.Contain:
        valueToUpperCase()
        if (typeof value1 == 'string') {
          return value1.split(',').some(v => String(value).includes(String(v)))
        }
        return value != null && String(value).includes(String(value1))
      case Condition.NotContain:
        valueToUpperCase()
        if (typeof value1 == 'string') {
          return value1.split(',').every(v => !String(value).includes(String(v)))
        }
        return value != null && !String(value).includes(String(value1))
      case Condition.StartsWith:
        valueToUpperCase()
        return value != null && String(value).startsWith(String(value1))
      case Condition.EndsWith:
        valueToUpperCase()
        return value != null && String(value).endsWith(String(value1))
    }
  })
}

/**
 * 查看类型转为表单控件的查看类型
 * @param type 类型
 * @returns type: string
 */
export function exchangeType(type: string) {
  switch (type) {
    case 'mapping':
    case 'html':
    case 'progress':
    case 'date':
    case 'time':
    case 'color':
    case 'datetime':
      return 'static-' + type;
    case 'number':
      return 'input-number';
    default:
      return type || 'static';
  }
}
//递归遍历super对象，查找某个属性的值
export function findField(obj: any, targetField: string): any {
  // 遍历对象的每一个属性
  if (obj.hasOwnProperty(targetField)) {
    return obj[targetField]
  } else if (obj.__super && JSON.stringify(obj.__super) !== '{}') {
    return findField(obj.__super, targetField)
  }
  // 如果没有找到目标字段，返回 undefined
  return undefined;
}

//多列排序
/**
 * @param tableData 原始数据
 * @param columnProperties 排序字段
 * @returns 排序后数据 obj<any>[]
 */
export function multiColumnSort(tableData: obj<any>[], columnProperties: string[]) {
  return tableData.sort((a, b) => {
    for (const property of columnProperties) {
      const valueA = a[property];
      const valueB = b[property];

      // 处理 null 和 undefined 值
      if (valueA === null || valueA === undefined) {
        if (valueB === null || valueB === undefined) {
          // 如果两者都是 null 或 undefined，则认为它们相等，继续比较下一列
          continue;
        } else {
          // 如果 valueA 是 null 或 undefined 而 valueB 不是，则认为 valueA 应该排在 valueB 之前
          return -1;
        }
      } else if (valueB === null || valueB === undefined) {
        // 如果 valueB 是 null 或 undefined 而 valueA 不是，则认为 valueA 应该排在 valueB 之后
        return 1;
      }

      // 正常比较非 null/undefined 的值
      if (typeof valueA === "number") {
        const comparison = valueA - valueB;
        if (comparison !== 0) return comparison;
      } else {
        const comparison = valueA.localeCompare(valueB, undefined, { sensitivity: 'accent' });
        if (comparison !== 0) return comparison;
      }
    }

    // 如果所有列都相同（包括 null/undefined 处理），则认为两个记录相等，返回0保持原顺序
    return 0;
  });
}

// 计算笛卡儿积
export const cartesianProduct = (...arrays: any[]): any[] => {
  if (arrays.length === 0) return [];
  if (arrays.length === 1) return arrays[0].map((x: any) => [x]);
  return cartesianProduct(...arrays.slice(0, -1)).reduce((acc: any[], val: any[]) => acc.concat(arrays[arrays.length - 1].map((x: any) => val.concat(x))), []);
}

export const openImageEnlarge = (data: Array<any>, baseURL: string, onImageEnlarge: any, env: any) => {
  let isNotImg = false;
  let list: any = data.map((item: any) => {
    isNotImg = !isImg(item.name);
    const _imgUrl = item.thumbnailAddr || item?.addr
    // 如果开始时http不进行拼接处理
    const imgUrl = _imgUrl?.startsWith?.("http") ? _imgUrl : ((baseURL ? baseURL : '') + _imgUrl)
    const originalSrc = item.preview?.startsWith?.("http") ? item.preview : ((baseURL ? baseURL : '') + item.preview)
    const downloadSrc = item?.addr?.startsWith?.("http") ? item?.addr : ((baseURL ? baseURL : '') + item?.addr)
    return {
      src: isNotImg
        ? getMediaIcon(item.name)
        : imgUrl,
      originalSrc: originalSrc,
      downloadSrc: downloadSrc,
      title: item.name || '',
      isNotImg
    };
  });
  if (isMobile()) {
    if (Shell.hasShell()) {
      if (tools.isAndroid) {
        Shell.previewFile({ urls: list.map((val: any) => { return val.originalSrc }) })
      } else {
        const urls = list.map((attachment: any) => {
          const url = new URL(encodeURI(attachment.originalSrc))
          const search = url.search == '' ? `?fileName=${Date.now() + attachment.title}` : `${url.search}&fileName=${Date.now() + attachment.title}`
          url.search = search
          return url.href
        })
        Shell.previewFile({ urls, current: 0 })
      }
      return
    } else if (env?.previewImagesMb) {
      const urls = list.map((val: any) => { return val.originalSrc })
      env.previewImagesMb(urls, 0)
      return
    }

  }
  onImageEnlarge &&
    onImageEnlarge({
      src: list[0].src,
      originalSrc: list[0].originalSrc,
      index: 0,
      list
    });
}

// 获取文本中的列名称 a[dd]ccccc[ee]ff 获取文本中的 dd 与 ee并返回
export const getNameInString = (valueStr: string): {
  orginStr: string,
  parseStr: string,
  parseObj: any,
} => {
  // 文本起始位置
  let index = 0
  // 转化文本
  let newStr = ''
  // 字段转化对应表
  const parseObj = {}

  // 括号计数
  let BracktCount = 0
  // 括号中的变量名
  let nameInBrackt = ''
  while (valueStr[index]) {
    const curStr = valueStr[index]
    // 如果遇到左括号计数+1 堆推入 跳过循环
    if (curStr === '[') {
      index++
      BracktCount++
      continue
    }
    // 如果遇到左括号计数-1 堆弹出
    if (curStr === ']' && BracktCount) BracktCount--
    // 还有括号计数的情况下 说明还在括号里面 记录变量字符串
    if (BracktCount) {
      nameInBrackt += curStr
    } else {
      // 如果没有括号计数但有暂存变量 增加新文本的值
      if (nameInBrackt) {
        nameInBrackt = `[${nameInBrackt}]`
        parseObj[nameInBrackt] = nameInBrackt[nameInBrackt] || `{$${Object.values(parseObj).length}}`
        // 字符串变化
        newStr += parseObj[nameInBrackt]
        nameInBrackt = ''
      } else {
        // 如果没有括号计数并且没有暂存变量 增加新文本的值
        newStr += curStr
      }
    }
    index++
  }

  return {
    orginStr: valueStr,
    parseStr: newStr,
    parseObj
  }
}