import XLSX, { CellObject } from 'xlsx'
import { IColumn } from '../store/table';

interface IHeadCell {
  name: string;
  label: string;
  colspan: number;
  rowspan: number;
  column: IColumn;
}

export const exportXLSX = (columns: any[], data: any[], fileName: string) => {
  // 创建工作簿和工作表
  const workbook = XLSX.utils.book_new();
  const worksheet = XLSX.utils.aoa_to_sheet([columns, ...data]);

  // 将工作表添加到工作簿
  XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1');

  // 将工作簿导出为二进制 Blob 对象
  const wbout = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' });

  // 创建隐藏的可下载链接
  const blob = new Blob([wbout], { type: 'application/octet-stream' });
  download(blob, fileName)
}

export const exportXLSXFromCross = (tableHeadRows: IHeadCell[][], columns: IColumn[], datas: any[], fileName: string, keepFormat: boolean = true) => {
  const headCellObjs = calcHeadCellObjs(tableHeadRows)
  const bodyCellObjs = calcBodyCellObjs(datas, columns, keepFormat)
  const workbook = XLSX.utils.book_new()
  const worksheet = XLSX.utils.aoa_to_sheet([])
  for (const cellObj of headCellObjs) {
    XLSX.utils.sheet_add_aoa(worksheet, [[cellObj]], { origin: cellObj.s })
  }
  XLSX.utils.sheet_add_aoa(worksheet, bodyCellObjs, { origin: { r: tableHeadRows.length, c: 0 } })
  worksheet['!merges'] = headCellObjs
  worksheet['!cols'] = columns.map(column => ({ width: typeof column.label == 'string' ? column.label.length * 3 : 20 }))
  XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1')
  XLSX.writeFile(workbook, fileName)
}

const calcHeadCellObjs = (tableHeadRows: IHeadCell[][]) => {
  const fn = (startRow: number, startCol: number, cell: IHeadCell, array: (XLSX.Range & CellObject)[]) => {
    const { rowspan, colspan } = cell
    const label = cell.rowspan == tableHeadRows.length - startRow ? cell.column.label : cell.label
    if (rowspan > 1 && colspan > 1) {
      array.push({ s: { r: startRow, c: startCol }, e: { r: startRow + rowspan - 1, c: startCol + colspan - 1 }, v: label, t: 's' })
      return startCol + colspan
    }
    if (rowspan > 1) {
      array.push({ s: { r: startRow, c: startCol }, e: { r: startRow + rowspan - 1, c: startCol }, v: label, t: 's' })
      return startCol + colspan
    }
    if (colspan > 1) {
      array.push({ s: { r: startRow, c: startCol }, e: { r: startRow, c: startCol + colspan - 1 }, v: label, t: 's' })
      return startCol + colspan
    }
    array.push({ s: { r: startRow, c: startCol }, e: { r: startRow + rowspan - 1, c: startCol + colspan - 1 }, v: label, t: 's' })
    return startCol + colspan
  }
  const result: (XLSX.Range & CellObject)[] = []
  for (let i = 0; i < tableHeadRows.length; i++) {
    const row = tableHeadRows[i]
    let startCol = 0
    for (let j = 0; j < i; j++) {
      const preRow = tableHeadRows[j].filter(item => item.name != 'SF_COUNT')
      for (const item of preRow) {
        if (item.rowspan > i) {
          startCol += item.colspan
        }
      }
    }
    for (const cell of row) {
      startCol = fn(i, startCol, cell, result)
    }
  }
  return result
}

const calcBodyCellObjs = (datas: any[], columns: IColumn[], keepFormat: boolean = true) => {
  return datas.map<CellObject[]>(data => columns.map(column => {
    const dataTypeArr = ['number', 'static-number', 'input-number', 'progress', 'static-progress']
    const isNumerical = dataTypeArr.includes(column.type)
    const isMapping = column.type == 'mapping'
    const isPercentage = column.pristine.isPercentage
    const prefix = column.pristine.prefix
    const name = column.name!
    const isCurrency = Boolean(prefix) && column.type == 'number'

    const precision = column.pristine.precision ?? 0
    const place = new Array(precision).fill(0).join('')

    const numFormat = precision > 0 ? `0.${place}_ ` : '0_ '
    const perFormat = precision > 0 ? `0.${place}%` : '0%'
    const curFormat =  `${prefix}#,##0.${place};${prefix}-#,##0.${place}` 
    const value = data[name] ?? undefined
    return {
      v: isPercentage && !isNaN(+value) ? +(value) / 100 : isMapping ? column.map?.[value]?.replace?.(/\n|\r|<[^>]*>/g, '') ?? value : value ?? '',
      t: isNumerical || isPercentage ? 'n' : 's',
      z: !keepFormat ? undefined : (isCurrency ? curFormat : isPercentage ? perFormat : isNumerical ? numFormat : undefined)
    }
  }))
}

const download = (blob: Blob, fileName: string) => {
  const url = URL.createObjectURL(blob);
  // 提供下载链接给用户
  const link = document.createElement('a');
  link.href = url;
  link.download = fileName;
  document.body.appendChild(link);
  link.click();
  document.body.removeChild(link);
  URL.revokeObjectURL(url);
}