import FileSaver from "file-saver";

// 用于生成唯一id以关联主从表
const uuid = () => {
  const temp_url = URL.createObjectURL(new Blob());
  const uuid = temp_url.toString();
  URL.revokeObjectURL(temp_url);
  return uuid.substr(uuid.lastIndexOf("/") + 1);
}

// 用于添加并合并多个className
const classNames = (...names: any[]) => {
  let currentNames: string[] = [];
  names.forEach((name) => {
    if (name) currentNames.push(name)
  });
  return currentNames.join(' ');
}

const extractTemplate = (str: {}) => {
  const regex: RegExp = /\$\{([^}]+)\}/g;

  return Object.values(str).map((_str: string) => {
    return _str.replace(regex, (match: any, item: any) => {
      return item
    })
  })
}

// 单双击同时存在的情况，直接使用ondblclick会同时触发两次单击事件，延迟单击执行时间
const singleAndDoubleClick = (() => {
  let isClick = false, clickNum = 0;
  return (obj: { singleClick?: Function, doubleClick?: Function, params?: any }) => {
    const { singleClick, doubleClick, params } = obj
    if (!doubleClick) {
      return singleClick && singleClick(params)
    }
    clickNum++
    if (isClick) return
    isClick = true
    setTimeout(() => {
      if (clickNum > 1) {
        doubleClick && doubleClick(params)
      } else {
        singleClick && singleClick(params)
      }
      clickNum = 0
      isClick = false
    }, 300);
  }
})()

// 是否是图片格式
const IMG_SUFFIX = ['jpg', 'jpeg', 'png', 'bmp', 'gif', 'tif', 'heic', 'webp']
const isImg = (fileName: string) => {
  if (!fileName || !fileName.includes('.')) return true
  const suffix = fileName.split('.').pop() || ''
  return IMG_SUFFIX.includes(suffix.toLocaleLowerCase())
}
// 是否是视频格式
const right_typ = ["wav", "mp4", "avi", "mp3"]
const isCon = (fileName: string) => {
  if (!fileName || !fileName.includes('.')) return true
  const suffix = fileName.split('.').pop() || ''
  return right_typ.includes(suffix.toLocaleLowerCase())
}
// 是否是pdf格式

const isPdf = (str: string) => {
  return /(.jpe?)g|(.png)|(.pdf)/i.test(str)
}
// 文件格式地址
const iconMap = {
  annex: './public/images/icon-annex-fill.png',
  doc: './public/images/icon-doc-fill.png',
  excel: './public/images/icon-excel-fill.png',
  img: './public/images/icon-img-fill.png',
  music: './public/images/icon-music-fill.png',
  pdf: './public/images/icon-pdf-fill.png',
  ppt: './public/images/icon-ppt-fill.png',
  txt: './public/images/icon-txt-fill.png',
  video: './public/images/icon-video-fill.png',
  zip: './public/images/icon-zip-fill.png',
}
const getMediaIcon = (fileName: string) => {
  let icon = '';
  let fileType = fileName?.split('.')?.pop() ?? '';
  switch (fileType.toLocaleLowerCase()) {
    case 'doc':
    case 'docx':
      icon = iconMap.doc;
      break;
    case 'xls':
    case 'xlsx':
      icon = iconMap.excel;
      break;
    case 'ppt':
    case 'pptx':
      icon = iconMap.ppt;
      break;
    case 'zip':
    case 'rar':
      icon = iconMap.zip;
      break;
    case 'jpg':
    case 'jpeg':
    case 'png':
    case 'gif':
    case 'tif':
    case 'bmp':
    case 'webp':
      icon = iconMap.img;
      break;
    case 'txt':
      icon = iconMap.txt;
      break;
    case 'wav':
    case 'mp4':
    case 'avi':
    case 'mp3':
      icon = iconMap.video;
      break;
    case 'pdf':
      icon = iconMap.pdf;
      break;
    default:
      icon = iconMap.annex;
      break;
  }
  return icon
}


// 文件夹大小,路径，文件夹名字，获取文件夹大小,导航条，
const downFile = async (chunk: any, url: any, name: string | undefined | null, percent: any,) => {

  // 路径。分流大小3M
  const chunkSize: number = 3145728
  chunk(url, chunkSize, name).then((res: any) => {
    if (res) {
      download(url, res, percent, chunkSize, name)
        .then(buffers => {
          const mime = "application/" + name?.split(".").pop()
          saveAs(buffers as Uint8Array, name as string, mime)
        })
    } else {
      downloadFile(url, name || '', true)
    }
  });
}
//下载不同源的图片
const downloadImage = async (url: string, filename: string | null | undefined) => {
  const response = await fetch(url, { method: 'GET', mode: 'cors' });
  const blob = await response.blob();
  const urlObject = URL.createObjectURL(blob);
  const link = document.createElement('a');
  link.href = urlObject;
  link.download = filename || '';
  link.click();
  URL.revokeObjectURL(urlObject); // 清理工作
}
// 文件下载--自lioncellfile迁徙
const downloadFile = (url: any, name: string | undefined | null, crossDomain?: boolean) => {
  return new Promise((resolve, reject) => {
    resolve('')
  }).then(res => {
    if(crossDomain) {
      downloadImage(url, name)
    } else {
      if (typeof url == 'object' && url instanceof Blob) {
        url = URL.createObjectURL(url); // 创建blob地址
      }
      var aLink = document.createElement('a');
      aLink.href = url;
      aLink.download = name || ''; // HTML5新增的属性，指定保存文件名，可以不要后缀，注意，file:///模式下不会生效
      var event;
      if (window.MouseEvent) event = new MouseEvent('click');
      else {
        event = document.createEvent('MouseEvents');
        event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
      }
      aLink.dispatchEvent(event);
    }
  })
}
// 
// 路径,文件大小,默认下载分流的大小，最大下载次数
const download = async (url: string, datacontent: number, percent: any, chunkSize = 524288, name: string | undefined | null, poolLimit = 5) => {
  const chunks = typeof chunkSize === "number" ? Math.ceil(datacontent / chunkSize) : 1;

  const results = await asyncPool(
    poolLimit, chunks, (i: number) => {
      let start = i * chunkSize;
      let end = i + 1 == chunks ? datacontent - 1 : (i + 1) * chunkSize - 1;
      return getBinaryContent(url, start, end, i, name, percent);
    })
  const sortedBuffers = results.map((item: any) => {
    const Buffers = item.buffer
    return new Uint8Array(Buffers)
  })

  return concatenate(sortedBuffers);
}

const asyncPool = async (poolLimit: number, array: any, iteratorFn: any,) => {

  const ret: any = []; // 存储所有的异步任务
  const executing: any = []; // 存储正在执行的异步任务
  for (let i = 0; i < array; i++) {
    // 调用iteratorFn函数创建异步任务
    const p = Promise.resolve().then(() => iteratorFn(i));
    ret.push(p); // 保存新的异步任务
    // 当poolLimit值小于或等于总任务个数时，进行并发控制
    if (poolLimit <= array) {
      // 当任务完成后，从正在执行的任务数组中移除已完成的任务
      const e: any = p.then(() => executing.splice(executing.indexOf(e), 1));
      executing.push(e); // 保存正在执行的异步任务
      if (executing.length >= poolLimit) {
        await Promise.race(executing); // 等待较快的任务执行完成
      }
    }
  }

  return Promise.all(ret);

}


const getBinaryContent = (url: string, start: number, end: number, i: number, name: any, percent?: any,) => {
  return new Promise((resolve, reject) => {
    try {
      const xhr = new XMLHttpRequest();
      xhr.open("GET", url, true);
      xhr.setRequestHeader("range", `bytes=${start}-${end}`); // 请求头上设置范围请求信息
      xhr.responseType = "arraybuffer"; // 设置返回的类型为arraybuffer
      xhr.onload = function () {
        percent(name);
        resolve({
          index: i, // 文件块的索引
          buffer: xhr.response, // 范围请求对应的数据
        });
      };
      xhr.send();
    } catch (err) {
      reject(new Error(err));
    }
  });
}
const concatenate = (arrays: any) => {
  if (!arrays.length) return null;
  const totalLength = arrays.reduce((acc: any, value: any) => acc + value.length, 0);
  const result = new Uint8Array(totalLength);
  let length = 0;
  for (let array of arrays) {
    result.set(array, length);
    length += array.length;
  }
  return result;
}
const saveAs = (buffers: Uint8Array, name: string, mime = "application/octet-stream") => {
  const blob = new Blob([buffers], {
    type: mime
  });
  // const blobUrl = URL.createObjectURL(blob);
  // const a = document.createElement("a");
  // a.download = name || "";
  // a.href = blobUrl;
  // a.style.display = 'none'
  // document.body.appendChild(a)
  // a.click();
  // a.remove();
  // URL.revokeObjectURL(blobUrl);
  FileSaver.saveAs(blob, name);
}


const copy = async (text: string) => {
  const execCommandCopay = () => {
    let input = document.createElement("textarea");
    input.style.cssText = 'position: absolute;top: -1px;height: 1px;width: 1px;';
    input.value = text;
    document.body.appendChild(input);
    input.select();
    document.execCommand("Copy");
    document.body.removeChild(input);
    return;
  }
  if (!navigator.clipboard) {
    execCommandCopay()
  } else {
    // 如果出现错误
    try {
      await navigator.clipboard.writeText(text).catch(() => {
        execCommandCopay()
      })
    } catch {
      execCommandCopay()
    }
  }
}

const createRandomValue = () => {
  let r, v, n;
  n = 'yyxxxxxx-yyxx-'.replace(/[xy]/g, (c) => {
    (r = (Math.random() * 16) | 0), (v = c == 'x' ? r : (r & 0x3) | 0x8);
    return v.toString(16);
  });
  return n + Date.now().toString(16);
}


const byteSize = (limit: number) => {
  var size = "";
  if (limit < 0.1 * 1024) {
    size = limit.toFixed(2) + "B"
  } else if (limit < 0.1 * 1024 * 1024) {
    size = (limit / 1024).toFixed(2) + "KB"
  } else if (limit < 0.1 * 1024 * 1024 * 1024) {
    size = (limit / (1024 * 1024)).toFixed(2) + "MB"
  } else {
    size = (limit / (1024 * 1024 * 1024)).toFixed(2) + "GB"
  }
  var sizeStr = size + "";
  var index = sizeStr.indexOf(".");
  var dou = sizeStr.substr(index + 1, 2)
  if (dou == "00") {
    return sizeStr.substring(0, index) + sizeStr.substr(index + 3, 2)
  }
  return size;
}

const getDiffRowData = (rowData: any[], diffObj: any[], primaryField: string, levelField: string, groupByField: string, groupFields: string) => {
  const groupFieldsArray = groupFields.split(',')
  let resultArray: any[] = []
  const levelFields = levelField.split(',')
  diffObj.forEach(obj => {
    const diffObj = obj?.diff || obj // 防止出现
    for (const key in diffObj) {
      if (key != primaryField && key != groupByField && !levelField.includes(key)) {
        const isGroupKey = groupFieldsArray.some(field => key.includes(field))
        if (isGroupKey) {
          const index = key.indexOf('_')
          const groupByFieldValue = key.substring(0, index)
          const groupByFieldName = key.substring(index + 1, key.length)
          const item = rowData.find(data => {
            for (let i = 0; i < levelFields.length; i++) {
              const field = levelFields[i]
              if (data[field] != diffObj[field]) {
                return false
              }
            }
            return data[groupByField] == groupByFieldValue
          })
          const idx = resultArray.findIndex(data => {
            for (let i = 0; i < levelFields.length; i++) {
              const field = levelFields[i]
              if (data[field] != item?.[field]) {
                return false
              }
            }
            return data[groupByField] == item[groupByField]
          })
          if (idx == -1) {
            const temp = item ? { ...item } : {}
            temp[groupByFieldName] = diffObj[key]
            resultArray.push(temp)
          } else {
            const temp = resultArray[idx]
            temp[groupByFieldName] = diffObj[key]
            resultArray[idx] = temp
          }
        } else {
          const items = rowData.filter(data => {
            for (let i = 0; i < levelFields.length; i++) {
              const field = levelFields[i]
              if (data[field] != diffObj[field]) {
                return false
              }
            }
            return true
          })
          items.forEach(item => {
            const idx = resultArray.findIndex(data => {
              for (let i = 0; i < levelFields.length; i++) {
                const field = levelFields[i]
                if (data[field] != item[field]) {
                  return false
                }
              }
              return data[groupByField] == item[groupByField]
            })
            if (idx == -1) {
              const temp = { ...item }
              temp[key] = diffObj[key]
              resultArray.push(temp)
            } else {
              const temp = resultArray[idx]
              temp[key] = diffObj[key]
              resultArray[idx] = temp
            }
          })
        }
      }
    }
  })
  return resultArray
}

export {
  extractTemplate,
  classNames,
  singleAndDoubleClick,
  isImg,
  getMediaIcon,
  downloadFile,
  uuid,
  copy,
  isCon,
  isPdf,
  downFile,
  createRandomValue,
  byteSize,
  getDiffRowData
}
