import {
  getKKFileViewURLFromMinioApi,
  queryFileIdByNodeIdApi,
  systemDataDownloadFileApi,
  getMinioPresignedUrlApi,
} from '@/api/data/data';
import { getDictionaryDataApi, getFormConfigureApi } from '@/api/system/systemData';
import { ElMessage } from 'element-plus';
import * as XLSX from 'xlsx';
import { cloneDeep } from 'lodash-es';
import { CommonStore } from '@/stores/common';
import dayjs from 'dayjs';
import { FILE_TYPE } from './enum/file';
import emitter from '@/utils/eventBus';
import { useDict } from './useDict';

const env = import.meta.env;

export const formatFileSize = (sizeInBytes: number): string => {
  if (sizeInBytes === undefined || sizeInBytes === null) {
    return '';
  }
  if (sizeInBytes < 0) {
    return '0 B';
  }
  const units = ['B', 'KB', 'MB', 'GB', 'TB'];
  let size = sizeInBytes;
  let unitIndex = 0;

  while (size >= 1024 && unitIndex < units.length - 1) {
    size /= 1024;
    unitIndex++;
  }

  return `${size.toFixed(2)} ${units[unitIndex]}`;
};

export const openTabReviewFile = async (fileId: number) => {
  const res: any = await getKKFileViewURLFromMinioApi({ fileId });
  if (res.code === 200) {
    window.open(env.VITE_API_FILE_PREVIEW_URL + '?' + res.data.encodeKKFileViewURL, '_blank');
    // return res.data.encodeKKFileViewURL;
  } else {
    ElMessage.error('获取文件预览地址失败!');
    return '';
  }
};

export class FileUtil {
  // 判断是否是图片
  static isPicture(fileUrl: string) {
    return (
      fileUrl.endsWith('.png') ||
      fileUrl.endsWith('.jpg') ||
      fileUrl.endsWith('.jpeg') ||
      fileUrl.endsWith('.webp') ||
      fileUrl.endsWith('.ico') ||
      fileUrl.endsWith('.bmp') ||
      fileUrl.endsWith('.svg') ||
      fileUrl.endsWith('.gif')
    );
  }
  /** 获取文件名后缀 */
  static getSuffixName(fileName: string) {
    const index = fileName.lastIndexOf('.');
    if (index > 0) {
      return fileName.substring(index + 1);
    }
    return fileName;
  }
  /** 获取无后缀的文件名 */
  static getNameByFileName(fileName: string) {
    return fileName.substring(0, fileName.lastIndexOf('.'));
  }

  /**
   * 根据文件id获取文件静态资源路径
   * @param fileId
   * @returns
   */
  static getFilePreviewImgPathUrl = (fileId: any) => {
    const url = `${env.VITE_API_IMAGE_PREVIEW_URL}/data/previewImage?fileId=${fileId}`;
    return url;
  };

  /**
   * 解析xlsx文件
   * @param file
   * @returns
   */
  static parsingExcelFile = (file: File) => {
    return new Promise((resolve) => {
      const reader = new FileReader();
      reader.readAsArrayBuffer(file);
      reader.onload = (e) => {
        const workbook = XLSX.read(e.target?.result, { type: 'array' });
        const firstSheetName = workbook.SheetNames[0];
        const worksheet = workbook.Sheets[firstSheetName];
        const arrData = XLSX.utils.sheet_to_json(worksheet, { header: 1 });
        resolve(arrData);
      };
    });
  };

  /**
     * 将tableData转换为xlsx文件导出
     * @param tableData 表格数据
     * @param excelName 导出表格名称
     * @param titleArr  表头标题（不传就导出所有属性）模版 [{ chineseName: '中文名',
      englishName: '英文属性',}]
     */
  static exportExcel(tableData: any, excelName: string, titleArr?: any) {
    const data: any = [];
    const keyArray = [];
    if (titleArr) {
      const englishTitle = titleArr.map((item: any) => {
        return item.englishName;
      });

      for (let i = 0; i < tableData.length; i++) {
        for (const key in tableData[i]) {
          if (!englishTitle.includes(key)) {
            delete tableData[i][key];
          }
        }
      }
    }
    const getLength = function (obj: any) {
      let count = 0;
      for (const i in obj) {
        if (obj.hasOwnProperty(i)) {
          count++;
        }
      }
      return count;
    };
    for (const key1 in tableData) {
      if (tableData.hasOwnProperty(key1)) {
        const element = tableData[key1];
        const rowDataArray: any = [];
        for (const key2 in element) {
          if (element.hasOwnProperty(key2)) {
            const element2 = element[key2];
            rowDataArray.push(element2);
            if (keyArray.length < getLength(element)) {
              keyArray.push(key2);
            }
          }
        }
        data.push(rowDataArray);
      }
    }
    // keyArray为英文字段表头
    const newArr = cloneDeep(keyArray);
    // 传了中英文表头列表就用中文表头
    if (titleArr) {
      for (let i = 0; i < newArr.length; i++) {
        for (let j = 0; j < titleArr.length; j++) {
          if (newArr[i] === titleArr[j].englishName) {
            newArr[i] = titleArr[j].chineseName;
          }
        }
      }
    }
    data.unshift(newArr);
    // data.splice(0, 0, keyArray, newArr);
    const ws = XLSX.utils.aoa_to_sheet(data);
    const wb = XLSX.utils.book_new();
    // 此处隐藏英文字段表头
    const wsrows: any = [{ hidden: false }];

    const cols = keyArray.map(() => {
      return {
        wch: 20,
      };
    });

    ws['!rows'] = wsrows; // ws - worksheet
    ws['!cols'] = cols; // ws - worksheet
    XLSX.utils.book_append_sheet(wb, ws, 'sheet');
    /* generate file and send to client */
    // const nowTime = moment().format('YYYY-MM-DD HH:mm:ss');
    XLSX.writeFile(wb, `${excelName}.xlsx`);
  }
}

// 导出文件
export const exportFile = (api: any, tableName: string, fileName: string, params: any) => {
  getFormConfigureApi({ formName: tableName }).then((res: any) => {
    if (res.code === 200) {
      const formConfig = JSON.parse(res.data.formConfig);
      const listData = formConfig
        .filter((item: any) => item.isShow)
        .map((item: any) => {
          const val: any = {
            key: item.key,
            title: item.title,
          };
          if (
            ['select', 'multipleSelect', 'radio', 'checkbox'].includes(item.inputMode) &&
            CommonStore().getDictData(item.formOptions)
          ) {
            val.dictCode = item.formOptions;
            val.dictData = CommonStore().getDictData(item.formOptions).O;
          }
          return val;
        });
      api(
        {
          excelHeaders: listData,
          params,
        },
        `${dayjs().format('YYYYMMDDHHmmss')}_${fileName || tableName}.xlsx`
      );
    }
  });
};

/**
 * 根据文件id下载文件
 * @param fileId
 */
export const downloadFileById = async (fileId: number) => {
  // 1.点击事件下载
  // const link = document.createElement('a');
  // link.href = `${env.VITE_API_FILE_URL}/data/downloadFile?fileId=${fileId}`;
  // document.body.appendChild(link);
  // link.click();
  // document.body.removeChild(link);
  // 2.文件流下载
  // await systemDataDownloadFileApi({ fileId });
  // 3.浏览器下载
  getMinioPresignedUrlApi({ fileId }).then((res: any) => {
    if (res.code === 200) {
      const downloadUrl = res.data.minioDownloadUrl;
      window.open(downloadUrl, '_blank');
    }
  });
};

// 文件流下载
export const downloadFileByStream = async (fileId: number) => {
  await systemDataDownloadFileApi({ fileId });
};

/**
 * 上传大文件
 * @param params 配置参数
 * @param params.fileList 文件列表[必填]
 * @param params.dirId 文件目录id[必填]
 * @param params.projectId 项目id[必填]
 * @param params.isApprove 0不需要审批 1需要审批 默认0[非必填]
 * @param params.callbackFlag 回调标识[非必填]
 * @param params.fileType 文件类型，不传组件内获取[非必填]
 * @param params.type 默认0[非必填]
 * @param api 分配api
 */
export const uploadBigFile = async (params: any, api: any) => {
  const sourceFiles: any = [];
  const fileList = params.fileList;
  // 给上传的文件新增对应的文件类型
  for (let i = 0; i < fileList.length; i++) {
    const file = fileList[i]?.raw || fileList[i];
    sourceFiles.push({
      fileName: file.name,
      size: file.size,
      raw: file,
      fileType: params.fileType ? params.fileType : fileUploadAllocationTypeFun(file.name),
    });
  }
  params = Object.assign(
    {
      taskType: 1, // 任务类型，用于区分回调接口
      sourceFiles,
      uploadTaskId: new Date().getTime(), // 用时间戳作为任务id
      type: 0,
    },
    params
  );
  delete params.fileList;
  const res = await api(params);
  if (res.code === 200) {
    res.data.forEach((item: any, index: number) => {
      emitter.emit('ADD_UPLOAD_FILE', {
        file: params.sourceFiles[index].raw,
        data: {
          ...item,
          isApprove: params.isApprove || 0,
          taskType: params.taskType,
          callbackFlag: params.callbackFlag || '',
        },
      });
    });
  }
};

/**
 * 根据节点id查询文件id
 * @param uuid
 * @returns
 */
export const queryFileIdByNodeIdFun = async (uuid: any) => {
  try {
    const res: any = await queryFileIdByNodeIdApi({ nodeId: uuid });
    if (res && res.code === 200) {
      return res?.data?.id;
    } else {
      return null;
    }
  } catch {
    return null;
  }
};

/**
 * 获取文件上传类型限制
 * @param code 字典类码
 * @param type str 字符串形式返回(.类型,.类型,.类型) list 数组形式返回([类型,类型,类型])
 */
export const getFileUploadAcceptFun = async (code: any, type: any = 'str') => {
  let str: any = '';
  let list: any = [];
  try {
    const res: any = await getDictionaryDataApi({ dictClass: code });
    if (res && res.code === 200) {
      if (type === 'str') {
        str = res.data
          .map((item: any) => {
            return `.${item.dictValue}`;
          })
          .join(',');

        return str;
      } else {
        list = res.data.map((item: any) => {
          return item.dictValue;
        });
        return list;
      }
    } else {
      if (type === 'str') {
        return str;
      } else {
        return list;
      }
    }
  } catch {
    if (type === 'str') {
      return str;
    } else {
      return list;
    }
  }
};

// 预览支持的文件类型 fileName文件名，viewType预览方式，不传就默认kkfile
export const isAcceptFileType = (fileName: any, viewType: string) => {
  if (!fileName) return false;
  const fileType = fileName.split('.').pop().toLowerCase();
  // 办公文件类型 kkfile onlyoffice都支撑
  const officeList = ['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'pdf', 'txt', 'csv', 'md'];
  // 以下只有kkfile支持
  const picList = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg', 'ico'];
  const compressList = ['zip', 'rar', '7z'];
  const videoList = ['mp3', 'mp4'];
  const codeList = ['html', 'css', 'js', 'json', 'py'];
  const kkSupportType = [...officeList, ...picList, ...compressList, ...videoList, ...codeList];
  if (viewType === 'onlyOffice') {
    return officeList.includes(fileType);
  } else {
    return kkSupportType.includes(fileType);
  }
};

/**
 * 根据文件名后缀自动匹配对应的文件类型
 * @param fileName 文件名
 * @returns
 */
export const fileUploadAllocationTypeFun = (fileName: string) => {
  let fileType: any = FILE_TYPE.MODEL_FILE;
  const { FILE_UPLOAD_ALLOCATION_TYPE }: any = useDict('FILE_UPLOAD_ALLOCATION_TYPE');
  const typeList = FILE_UPLOAD_ALLOCATION_TYPE.value.A || [];

  for (let i = 0; i < typeList.length; i++) {
    const suffixs = typeList[i].value.split(',');
    for (let j = 0; j < suffixs.length; j++) {
      if (fileName.endsWith(suffixs[j])) {
        fileType = typeList[i].label;
      }
    }
  }

  return fileType;
};

// 根据文件名后缀自动匹配对应的icon
// 根据文件名后缀自动匹配对应的icon
import folderIcon from '@/assets/imgs/fileIcon/folder.png';
import wordIcon from '@/assets/imgs/fileIcon/word.png';
import xlsIcon from '@/assets/imgs/fileIcon/xls.png';
import pptIcon from '@/assets/imgs/fileIcon/ppt.png';
import pdfIcon from '@/assets/imgs/fileIcon/pdf.png';
import txtIcon from '@/assets/imgs/fileIcon/txt.png';
import zipIcon from '@/assets/imgs/fileIcon/zip.png';
import imgIcon from '@/assets/imgs/fileIcon/img.png';
import codeIcon from '@/assets/imgs/fileIcon/code.png';
import csvIcon from '@/assets/imgs/fileIcon/csv.png';
import mdIcon from '@/assets/imgs/fileIcon/md.png';
import jsonIcon from '@/assets/imgs/fileIcon/json.png';
import mp3Icon from '@/assets/imgs/fileIcon/mp3.png';
import mp4Icon from '@/assets/imgs/fileIcon/mp4.png';
import otherIcon from '@/assets/imgs/fileIcon/other.png';
import pythonIcon from '@/assets/imgs/fileIcon/python.png';
import h5Icon from '@/assets/imgs/fileIcon/h5.png';
import xmlIcon from '@/assets/imgs/fileIcon/xml.png';

type IconEntry = {
  icon: string;
  exts: string[];
};

const iconMap: Record<string, IconEntry> = {
  word: { icon: wordIcon, exts: ['doc', 'docx'] },
  xls: { icon: xlsIcon, exts: ['xls', 'xlsx'] },
  ppt: { icon: pptIcon, exts: ['ppt', 'pptx'] },
  pdf: { icon: pdfIcon, exts: ['pdf'] },
  txt: { icon: txtIcon, exts: ['txt'] },
  zip: { icon: zipIcon, exts: ['zip', 'rar', '7z'] },
  img: { icon: imgIcon, exts: ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg', 'ico'] },
  folder: { icon: folderIcon, exts: [''] },
  code: { icon: codeIcon, exts: ['html', 'css', 'js'] },
  python: { icon: pythonIcon, exts: ['py'] },
  h5: { icon: h5Icon, exts: ['h5'] },
  csv: { icon: csvIcon, exts: ['csv'] },
  md: { icon: mdIcon, exts: ['md'] },
  json: { icon: jsonIcon, exts: ['json'] },
  mp3: { icon: mp3Icon, exts: ['mp3'] },
  mp4: { icon: mp4Icon, exts: ['mp4'] },
  xml: { icon: xmlIcon, exts: ['xml'] },
  other: { icon: otherIcon, exts: [] },
};

export const fileUploadAllocationIconFun = (fileName: string) => {
  const arr = fileName?.split('.');
  const fileType = arr.length > 1 ? arr.pop()?.toLowerCase() : '';
  if (fileType === '') {
    return iconMap.folder.icon;
  } else {
    const iconEntry =
      Object.values(iconMap).find((entry) => entry.exts.includes(fileType as string)) ||
      iconMap.other;
    return iconEntry.icon;
  }
};
