import * as XLSX from 'xlsx';
import ExcelJS from 'exceljs';
import { message } from 'antd';
import { httpConfig } from 'containers/config/httpConfig';
/**
  exportExcel方法需要传入的参数
    1、headers --- 表头
    2、data --- 表格数据
    3、name --- 导出表格的名称，默认为导出表格数据
    4、arr --- 数组，每个单元格的大小，每个对象的key只必须是 wpx
    注意，导出表格的格式只能为xlsx，别的格式可能没数据或者不支持那种格式
 */

let windowHost = window.location && window.location.protocol && window.location.host ? (window.location.protocol + '//' + window.location.host) : (window.location && window.location.origin ? window.location.origin : '');
let ipDefault = windowHost && (windowHost.indexOf('localhost') !== -1 || windowHost.indexOf('127.0.0.1') !== -1) ? httpConfig.ipDeault : windowHost;

// 将pdf的base64格式转换为Blob
function base64toBlob(b64Data, contentType, sliceSize = 4) {
  let b = b64Data.toString();
  b64Data = b.split(',')[1];
  var byteCharacters = atob(b64Data);
  var byteArrays = [];
  for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
    var slice = byteCharacters.slice(offset, offset + sliceSize);
    var byteNumbers = new Array(slice.length);
    for (let i = 0; i < slice.length; i++) {
      byteNumbers[i] = slice.charCodeAt(i);
    }
    var byteArray = new Uint8Array(byteNumbers);
    byteArrays.push(byteArray);
  }
  var blob = new Blob(byteArrays, { type: contentType });
  return blob;
}

const getColumnName = (index) => {
  let columnName = '';
  while (index >= 0) {
    columnName = String.fromCharCode(65 + (index % 26)) + columnName;
    index = Math.floor(index / 26) - 1;
  }

  return columnName;
}

let handleExcel = {
  // 导出 Excel - exportExcelWithXlsx
  exportExcel(headers, data, name = '导出表格数据', arr, format, sheetName) {
    try {
      let fileName = name + '.' + (format || 'xlsx');
      let headerData = []
      for (var i = 0; i < headers.length; i++) {
        headerData.push({ wpx: parseInt(headers[i].width || 100) })
      }
      // 单元格的大小
      let wpxArr = arr && arr.length > 0 ? arr : headerData;
      const hasParentTitle = headers.some(header => 'parentTitle' in header);
      let _headers = {};
      let _subHeaders = {};
      let merges = [];
      if (!hasParentTitle) { // 只有一级标题 - 按之前的逻辑走
        _headers = headers
          .map((item, i) => Object.assign({}, {
            dataIndex: item.dataIndex,
            title: typeof (item.title) === 'string' ? item.title : item.descripts,
            position: getColumnName(i) + '1'
          }))
          .reduce((prev, next) => Object.assign({}, prev, { [next.position]: { dataIndex: next.dataIndex, v: next.title } }), {});
      } else { // 二级表头，当有 parentTitle等于title时，合并单元格，否则不合并
        let currentParentTitle = '';
        let mergeStartIndex = 0;
        for (let i = 0; i < headers.length; i++) {
          let title = typeof (headers[i]?.title) === 'string' ? headers[i].title : (headers[i]?.descripts || '');
          let parentTitle = headers[i]?.parentTitle || '';
          if (parentTitle && title !== parentTitle) {
            if (currentParentTitle !== parentTitle) {
              merges.push({ s: { r: 0, c: mergeStartIndex }, e: { r: 0, c: i - 1 } });
              _headers[getColumnName(i) + '1'] = { v: parentTitle, s: { font: { bold: true }, fill: 'FF0000' } };
              mergeStartIndex = i;
            }
            currentParentTitle = parentTitle;
            _subHeaders[getColumnName(i) + '2'] = { v: title, s: { font: { bold: true }, fill: 'FF0000' } };
          } else if (!parentTitle || title === parentTitle) {
            merges.push({ s: { r: 0, c: i }, e: { r: 1, c: i } });
            _headers[getColumnName(i) + '1'] = { v: title, s: { font: { bold: true }, fill: 'FF0000' } };
            currentParentTitle = '';
          }
        }
        // 检查最后一个父标题是否需要合并
        if (mergeStartIndex < headers.length) {
          merges.push({ s: { r: 0, c: (mergeStartIndex) }, e: { r: 0, c: (headers.length - 1) } });
          currentParentTitle = '';
        }
      }
      const outputHeaders = Object.assign({}, _headers, _subHeaders);
      const _data = data
        .map((item, i) => headers.map((headerItem, j) => Object.assign({}, {
          content: item[headerItem.dataIndex],
          position: getColumnName(j) + (hasParentTitle ? (i + 3) : (i + 2))
        })))
        // 对刚才的结果进行降维处理（二维数组变成一维数组）
        .reduce((prev, next) => prev.concat(next))
        // 转换成 worksheet 需要的结构
        .reduce((prev, next) => Object.assign({}, prev, { [next.position]: { v: next.content } }), {});
      // 合并 headers 和 data
      const output = Object.assign({}, outputHeaders, _data);
      // 获取所有单元格的位置
      const outputPos = Object.keys(output);
      // 计算出范围 ,["A1",..., "H2"]
      const ref = `${outputPos[0]}:${outputPos[outputPos.length - 1]}`;
      // 构建 workbook 对象
      const wb = {
        SheetNames: [sheetName || 'mySheet'],
        Sheets: {
          [sheetName || 'mySheet']: Object.assign(
            {},
            output,
            {
              '!ref': ref,
              '!cols': wpxArr,
              '!merges': merges,
            },
          ),
        },
      };

      XLSX.writeFile(wb, fileName, (err) => {
        if (err) {
          message.error(err)
        }
      });
    } catch (error) {
      console.log('导出异常', error);
    }
  },

  // excelJS导出【通过parentTitle字段判断是否有二级表头，和title相同则合并单元格】
  exportExcelWithExcelJs(headers, data, name, format, sheetName) {
    try {
      // 初始化默认参数
      name = name || 'excel数据导出';
      format = format || 'xlsx';
      sheetName = sheetName || 'mySheet';
      if (!headers || headers.length === 0) {
        message.error('导出异常，请检查表头配置');
        return;
      }
      const workbook = new ExcelJS.Workbook();
      const worksheet = workbook.addWorksheet(sheetName);

      // 处理二级表头
      const hasParentTitle = headers.some(header => 'parentTitle' in header);
      if (hasParentTitle) {
        let currentParentTitle = '';
        let mergeStartIndex = 0;
        for (let i = 0; i < headers.length; i++) {
          let title = typeof (headers[i]?.title) === 'string' ? headers[i].title : (headers[i]?.descripts || '');
          let parentTitle = headers[i]?.parentTitle || '';
          if (parentTitle && title !== parentTitle) {
            if (currentParentTitle !== parentTitle) {
              if (currentParentTitle) {
                worksheet.getCell(getColumnName(mergeStartIndex) + '1').value = currentParentTitle;
                worksheet.getCell(getColumnName(mergeStartIndex) + '1').alignment = { horizontal: headers[i]?.align || 'center', vertical: 'middle' };
                if (parentTitle.includes('*') || headers[i]?.requireFlag === 'Y') {
                  worksheet.getCell(getColumnName(mergeStartIndex) + '1').font = { bold: true, color: { argb: 'FFFF0000' } };
                }
                worksheet.mergeCells(getColumnName(mergeStartIndex) + '1:' + getColumnName(i - 1) + '1');
              }
              mergeStartIndex = i;
            }
            worksheet.getCell(getColumnName(i) + '2').value = title;
            worksheet.getCell(getColumnName(i) + '2').alignment = { horizontal: headers[i]?.align || 'center', vertical: 'middle' };
            if (title.includes('*') || headers[i]?.requireFlag === 'Y') {
              worksheet.getCell(getColumnName(i) + '2').font = { bold: true, color: { argb: 'FFFF0000' } };
            }
            currentParentTitle = parentTitle;
          } else {
            worksheet.mergeCells(getColumnName(i) + '1:' + getColumnName(i) + '2');
            worksheet.getCell(getColumnName(i) + '1').value = title;
            worksheet.getCell(getColumnName(i) + '1').alignment = { horizontal: headers[i]?.align || 'center', vertical: 'middle' };
            if (title.includes('*') || headers[i]?.requireFlag === 'Y') {
              worksheet.getCell(getColumnName(i) + '1').font = { bold: true, color: { argb: 'FFFF0000' } };
            }
            currentParentTitle = '';
          }
        }
        let lastParentTitle = headers[headers.length - 1]?.parentTitle || ''; // 最后一个父标题
        // 检查最后一个父标题是否需要合并
        if (mergeStartIndex !== 0 && mergeStartIndex <= headers.length && currentParentTitle === lastParentTitle) {
          worksheet.getCell(getColumnName(mergeStartIndex) + '1').value = currentParentTitle;
          worksheet.getCell(getColumnName(mergeStartIndex) + '1').alignment = { horizontal: headers[mergeStartIndex]?.align || 'center', vertical: 'middle' };
          if (currentParentTitle.includes('*') || headers[mergeStartIndex]?.requireFlag === 'Y') {
            worksheet.getCell(getColumnName(mergeStartIndex) + '1').font = { bold: true, color: { argb: 'FFFF0000' } };
          }
          worksheet.mergeCells(getColumnName(mergeStartIndex) + '1:' + getColumnName(headers.length - 1) + '1');
          currentParentTitle = '';
        }
      } else {
        for (let j = 0; j < headers.length; j++) {
          let headCell = worksheet.getRow(1).getCell(j + 1);
          let value = headers[j]?.title || headers[j]?.descripts || '';
          headCell.value = value; // 根据你的数据结构可能需要调整
          headCell.alignment = { horizontal: headers[j]?.align || 'center', vertical: 'middle' };
          if (value.includes('*') || headers[j]?.requireFlag === 'Y') {
            headCell.font = { bold: true, color: { argb: 'FFFF0000' } };
          }
        }
      }
      // 填充数据
      for (let j = 0; j < headers.length; j++) {
        worksheet.getColumn(j + 1).width = (parseInt(headers[j]?.width || 100) / 8.43);
        for (let k = 0; k < data.length; k++) {
          let rowContentCell = worksheet.getRow(k + (hasParentTitle ? 3 : 2)).getCell(j + 1);  // 数据从第二行开始, 因此是 `k+2`
          rowContentCell.value = data[k][headers[j].dataIndex];   // 根据你的数据结构可能需要调整
          rowContentCell.alignment = { horizontal: headers[j]?.align || 'center', vertical: 'middle' };
        }
      }
      workbook.xlsx.writeBuffer().then(function (buffer) {
        const blob = new Blob([buffer], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" });
        let url = window.URL.createObjectURL(blob);
        let anchor = document.createElement('a');
        anchor.href = url;
        anchor.download = name + '.' + format;
        anchor.click();
      });
    } catch (error) {
      console.error('导出Excel时发生错误:', error);
    }
  },

  // 后台导出，前端用iframe链接地址
  downloadExcel(url, fn) {
    if (!url || (Array.isArray(url) && url.length === 0)) {
      console.warn('没有提供可供下载的有效URL！');
      return;
    }
    if (Array.isArray(url) && url.length > 0) {
      for (let i = 0; i < url.length; i++) {
        handleExcel.downloadSingleExcel(url[i], fn, i, url.length);
      }
    } else if (url) {
      handleExcel.downloadSingleExcel(url, fn);
    }
  },

  // 下载单个
  downloadSingleExcel(url, fn, currentIndex, totalLen) {
    if (!url) {
      message.error('导出异常，请稍后重试。');
      return;
    }
    try {
      var iframeElement = document.createElement('iframe');
      iframeElement.src = ipDefault + url;
      iframeElement.style.display = 'none';
      document.body.appendChild(iframeElement);
      if (totalLen && typeof totalLen === 'number' && typeof currentIndex === 'number' && currentIndex !== null && currentIndex !== undefined && currentIndex !== '') {
        if ((totalLen.length - 1 === currentIndex)) {
          fn && fn(); // 在满足条件时触发回调函数
        }
      } else {
        fn && fn();
      }
      // 防止下载两次
      setTimeout(function () {
        document.body.removeChild(iframeElement);
      }, 1000);
    } catch (error) {
      console.error('下载Excel时发生错误:', error);
      // 可以考虑在此处添加更详细的错误处理逻辑
    }
  },

  downloadPDF(base64Str, url, pdfName) {
    try {
      if (base64Str) {
        base64Str = 'data:application/pdf;base64,' + base64Str;
        let pdfFile = base64toBlob(base64Str, 'application/pdf');
        const blob = new Blob([pdfFile], { type: 'application/pdf' });  //指定打印文件类型pdf
        const downloadElement = document.createElement('a');
        const href = window.URL.createObjectURL(blob); // 创建下载的链接
        downloadElement.href = href;
        downloadElement.download = decodeURI(pdfName); // 下载后文件名
        document.body.appendChild(downloadElement);
        downloadElement.click(); // 点击下载
        document.body.removeChild(downloadElement); // 下载完成移除元素
        window.URL.revokeObjectURL(href); // 释放掉blob对象
      } else {
        let openUrl = ipDefault + url;
        window.open(openUrl);
      }
    } catch (error) {
      console.log('error', error);
    }
  },

  importExcel(file, type) {
    return new Promise((resolve, reject) => {
      const reader = new FileReader();
      // 读取Excel文件
      reader.onload = (e) => {
        const data = new Uint8Array(e.target.result);
        const workbook = XLSX.read(data, { type: 'array', cellDates: true });
        // 获取第一个工作表
        const worksheetName = workbook.SheetNames[0];
        const worksheet = workbook.Sheets[worksheetName];
        // 将工作表转换为JSON对象数组
        const jsonData = XLSX.utils.sheet_to_json(worksheet, { header: 'A', blankrows: false, defval: '' });
        jsonData.forEach(row => {
          Object.keys(row).forEach(key => {
            if (row[key] instanceof Date) { // 日期处理
              // 获取本地时间偏移量并转为分钟
              let timezoneOffset = row[key].getTimezoneOffset() * 60000;
              // 创建新的 Date 对象，减去时区偏移量
              let localDate = new Date(row[key].getTime() - timezoneOffset);
              let year = localDate.getFullYear();
              let month = (localDate.getMonth() + 1).toString().padStart(2, '0');
              let date = localDate.getDate().toString().padStart(2, '0');
              row[key] = `${year}-${month}-${date}`;
            }
          });
        });
        if (type === 'keyVal') { // 第一行作为数据的key值，其他的数据作为val值，返回成列表需要的数据格式。栗子：[{dataIndex: 'code', width: '150px'}]
          let [columnData, ...dataRows] = jsonData;
          let tableData = dataRows.map(row => {
            return Object.fromEntries(Object.entries(columnData).map(([key, value]) => [value, row[key]]));
          });
          resolve(tableData);
        } else {
          resolve(jsonData);
        }
      };
      reader.onerror = () => {
        reject(reader.error);
      };
      reader.readAsArrayBuffer(file);
    });
  }
};

export { handleExcel };