<template>
  <div>
    <div
      ref="spreadsheetRef"
      class="spreadsheet-container"
      id="spreadsheet"
    ></div>
  </div>
</template>

<script setup>
import { ref, onMounted, watch, computed } from "vue"
import Spreadsheet from "x-data-spreadsheet"
import { indexedColors } from "./color"
// import zhCN from "x-data-spreadsheet/dist/locale/zh-cn"
import _ from "lodash-es"
import tinycolor from "tinycolor2"
// Spreadsheet.locale("zh-cn", zhCN)

// Props 定义
const props = defineProps({
  workbook: Object,
})

// 响应式状态
const spreadsheet = ref(null)
const themeColors = ref([])
const spreadsheetRef = ref(null)

// 计算属性
const sheets = computed(() => {
  if (props.workbook.worksheets) {
    return props.workbook.worksheets.filter((sheet) => sheet._rows.length)
  }
  return []
})

// 方法
const initSpreadsheet = () => {
  // 优化性能配置
  spreadsheet.value = new Spreadsheet(spreadsheetRef.value, {
    view: {
      height: () => document.documentElement.clientHeight - 120,
      width: () => document.documentElement.clientWidth - 40,
    },
    mode: "read", // 只读模式
    showToolbar: false,
    showGrid: true,
    showContextmenu: false, // 禁用右键菜单提高性能
    multipleSheets: true,
    rpx: 1, // 减少渲染计算
    row: {
      len: 100, // 限制初始行数
      height: 25, // 固定行高
      autoHeight: true,
    },
    col: {
      len: 26, // 限制初始列数
      width: 50, // 固定列宽
      indexWidth: 60, // 行索引宽度
      minWidth: 30, // 最小列宽
      autoWidth: true, // 自动调整列宽
    },
    style: {
      // 确保默认样式正确
      bgcolor: "#ffffff",
      color: "#333333",
      align: "left",
      valign: "middle",
      textwrap: false,
      strike: false,
      underline: false,
      italic: false,
      bold: false,
      fontSize: 12,
    },
  }).loadData({})

  // 延迟加载数据，避免初始化时卡死
  updateTable()
}

const updateSpreadsheet = () => {
  if (!spreadsheet.value) return
  // 显示加载状态
  spreadsheetRef.value.classList.add("loading")
  try {
    const data = convertWorksheetToData()
    if (spreadsheet.value) {
      spreadsheetRef.value.innerHTML = ""
    }
    // 重新创建实例
    spreadsheet.value = new Spreadsheet(spreadsheetRef.value, {
      view: {
        height: () => document.documentElement.clientHeight - 120,
        width: () => document.documentElement.clientWidth - 40,
      },
      mode: "read",
      showToolbar: false,
      showGrid: true,
      showContextmenu: false,
      multipleSheets: true,
      rpx: 1,
      row: {
        len: 100,
        height: 25,
        autoHeight: true,
      },
      col: {
        len: 26,
        width: 50,
        indexWidth: 60,
        minWidth: 30,
        autoWidth: true,
      },
    }).loadData(data)
  } finally {
    spreadsheetRef.value.classList.remove("loading")
  }
}

const convertWorksheetToData = () => {
  let data = []
  sheets.value.forEach((sheet) => {
    const sheetIndex = sheet.id
    const sheetData = {
      name: sheet._name,
      freeze: "A1",
      styles: [
        {
          bgcolor: "#ffffff",
          color: "#000000",
          align: "left",
          valign: "middle",
          fontSize: 12,
        },
      ],
      merges: [],
      rows: {},
      cols: {},
    }
    try {
      // 预处理合并单元格
      processMerges(sheet, sheetData)
      // 预处理样式缓存，避免重复创建相同样式
      const styleCache = new Map()
      // 处理单元格数据
      processRows(sheet, sheetData, styleCache)
      // 处理列宽
      processColumns(sheet, sheetData)
      data.push(sheetData)
    } catch (error) {
      data[sheetIndex] = {
        name: sheet._name || "Sheet1",
        rows: {},
        cols: {},
      }
    }
  })
  return data
}

// 处理合并单元格
const processMerges = (sheet, sheetData) => {
  if (!sheet._merges) return

  Object.values(sheet._merges).forEach((merge) => {
    const { top, left, bottom, right } = merge
    sheetData.merges.push(
      `${columnIndexToLetter(left - 1)}${top}:${columnIndexToLetter(
        right - 1
      )}${bottom}`
    )
  })
}

// 处理行和单元格数据
const processRows = (sheet, sheetData, styleCache) => {
  // 增加最大行数限制，确保所有行都能显示
  const maxRows = Math.min(sheet.rowCount || 50, 100)

  // 预处理所有行，确保即使空行也能被处理
  for (let rowIndex = 0; rowIndex < maxRows; rowIndex++) {
    const row = sheet.getRow(rowIndex + 1)

    // 初始化行数据和行高
    let maxHeight = 25 // 最小行高
    sheetData.rows[rowIndex] = {
      cells: {},
      height: maxHeight,
    }

    // 如果行不存在，创建一个空行
    if (!row || !row.cellCount) {
      continue
    }

    // 处理行中的单元格
    // 使用列数而不是cellCount，确保处理所有可能的单元格
    const maxCols = Math.min(sheet.columnCount || 26, 100)
    for (let colIndex = 0; colIndex < maxCols; colIndex++) {
      try {
        const cell = row.getCell(colIndex + 1)
        if (!cell || (cell.type === "null" && !cell.style)) {
          // 对于空单元格，添加一个默认样式的空单元格
          sheetData.rows[rowIndex].cells[colIndex] = {
            text: "",
            style: 0,
          }
          continue
        }

        // 获取单元格文本和样式
        const { text: cellText, height: cellHeight } =
          getCellTextAndHeight(cell)
        const styleIndex = getCellStyle(cell, styleCache, sheetData.styles)
        // 更新行高
        maxHeight = Math.max(maxHeight, cellHeight)

        // 检查是否是合并单元格的起始单元格
        const mergeInfo = Object.values(sheet._merges || {}).find(
          (m) => m.top === row.number && m.left === colIndex + 1
        )

        // 设置单元格数据
        if (mergeInfo) {
          sheetData.rows[rowIndex].cells[colIndex] = {
            text: cellText,
            style: styleIndex,
            merge: [
              mergeInfo.bottom - mergeInfo.top,
              mergeInfo.right - mergeInfo.left,
            ],
          }
        } else {
          sheetData.rows[rowIndex].cells[colIndex] = {
            text: cellText,
            style: styleIndex,
          }
        }
      } catch (error) {
        sheetData.rows[rowIndex].cells[colIndex] = {
          text: "",
          style: 0,
        }
      }
    }

    // 更新行高
    sheetData.rows[rowIndex].height = maxHeight
  }
}

// 获取单元格文本和计算高度
const getCellTextAndHeight = (cell) => {
  let cellText = ""
  try {
    // 处理不同类型的单元格内容
    if (!cell || cell.value === null || cell.value === undefined) {
      cellText = ""
    } else if (
      cell.type === "date" ||
      (cell.numFmt &&
        (cell.numFmt.includes("yy") ||
          cell.numFmt.includes("mm") ||
          cell.numFmt.includes("dd") ||
          cell.numFmt.includes("h") ||
          cell.numFmt.includes("m:s")))
    ) {
      // 处理日期类型或带有日期格式的数字
      try {
        // 检查是否为日期值
        let date
        if (cell.value instanceof Date) {
          date = cell.value
        } else if (typeof cell.value === "number") {
          // Excel日期是从1900年1月1日开始的天数
          // 需要转换为JavaScript日期
          const excelEpoch = new Date(1899, 11, 30) // Excel的起始日期
          date = new Date(
            excelEpoch.getTime() + cell.value * 24 * 60 * 60 * 1000
          )
        } else {
          date = new Date(cell.value)
        }

        if (!isNaN(date.getTime())) {
          // 格式化日期
          const year = date.getFullYear()
          const month = (date.getMonth() + 1).toString().padStart(2, "0")
          const day = date.getDate().toString().padStart(2, "0")

          // 检查是否需要显示时间
          if (
            cell.numFmt &&
            (cell.numFmt.includes("h") || cell.numFmt.includes("s"))
          ) {
            const hour = date.getHours().toString().padStart(2, "0")
            const minute = date.getMinutes().toString().padStart(2, "0")
            const second = date.getSeconds().toString().padStart(2, "0")
            cellText = `${year}/${month}/${day} ${hour}:${minute}:${second}`
          } else {
            cellText = `${year}/${month}/${day}`
          }
        } else {
          // 如果不是有效日期，使用原始文本
          cellText = String(cell.text || cell.value || "")
        }
      } catch (e) {
        cellText = String(cell.text || cell.value || "")
      }
    } else if (typeof cell.value === "object" && cell.value !== null) {
      if (cell.value.hyperlink) {
        cellText = "[链接]"
      } else if (cell.value.image) {
        cellText = "[图片]"
      } else if (cell.value.richText) {
        cellText = cell.value.richText
          .map((t) => String(t?.text || ""))
          .join("")
      } else {
        cellText = String(cell.text || "")
      }
    } else if (cell.formula) {
      // 检查公式结果是否可能是日期
      if (
        cell.numFmt &&
        (cell.numFmt.includes("yy") ||
          cell.numFmt.includes("mm") ||
          cell.numFmt.includes("dd"))
      ) {
        try {
          // 尝试将结果转换为日期
          const excelEpoch = new Date(1899, 11, 30)
          const date = new Date(
            excelEpoch.getTime() + cell.result * 24 * 60 * 60 * 1000
          )

          if (!isNaN(date.getTime())) {
            const year = date.getFullYear()
            const month = (date.getMonth() + 1).toString().padStart(2, "0")
            const day = date.getDate().toString().padStart(2, "0")
            cellText = `${year}-${month}-${day}`
          } else {
            cellText = String(cell.result || cell.value || "")
          }
        } catch (e) {
          cellText = String(cell.result || cell.value || "")
        }
      } else {
        cellText =
          cell.result !== undefined && cell.result !== null
            ? String(cell.result)
            : String(cell.value || "")
      }
    } else {
      cellText =
        cell.text !== undefined && cell.text !== null
          ? String(cell.text)
          : cell.value !== undefined && cell.value !== null
          ? String(cell.value)
          : ""
    }
  } catch (e) {
    cellText = "[格式错误]"
  }

  // 计算行高
  const lineBreaks = ((cellText || "").match(/\n/g) || []).length + 1
  const chars = [...(cellText || "")]
  const lines = Math.ceil(chars.length / 40)
  const neededHeight = Math.max(lineBreaks, lines) * 20

  return { text: cellText, height: neededHeight }
}

// 获取单元格样式
const getCellStyle = (cell, styleCache, styles) => {
  // 创建样式对象
  const cellStyle = {
    bgcolor: "#ffffff",
    color: "#000000",
    align: cell.alignment?.horizontal || "left",
    valign: cell.alignment?.vertical || "middle",
    fontSize: cell.font?.size || 12,
    textwrap: true,
    bold: cell.font?.bold,
    italic: cell.font?.italic,
    underline: false,
    strike: false,
  }

  // 处理背景色
  if (cell.fill && cell.fill.type === "pattern") {
    const fgColor = cell.fill.fgColor || {}
    if (typeof fgColor.indexed === "number") {
      const indexedColor = indexedColors[fgColor.indexed]
      if (indexedColor) {
        cellStyle.bgcolor = `#${indexedColor}`
      }
    }
    // 处理主题颜色
    else if (typeof fgColor.theme === "number") {
      // Excel主题颜色索引映射
      const themeColorMap = {
        0: 1, // 浅色1
        1: 0, // 深色1
        2: 3, // 浅色2
        3: 2, // 深色2
        4: 4, // 强调色1
        5: 5, // 强调色2
        6: 6, // 强调色3
        7: 7, // 强调色4
        8: 8, // 强调色5
        9: 9, // 强调色6
      }

      const mappedIndex =
        themeColorMap[fgColor.theme] !== undefined
          ? themeColorMap[fgColor.theme]
          : fgColor.theme
      if (themeColors.value[mappedIndex]) {
        let color = `#${themeColors.value[mappedIndex]}`
        // 应用色调调整
        if (typeof fgColor.tint === "number" && fgColor.tint !== 0) {
          color = applyTint(color, fgColor.tint)
        }

        cellStyle.bgcolor = color
      }
    }
    // 处理RGB颜色
    else if (fgColor.rgb) {
      cellStyle.bgcolor = `#${fgColor.rgb.substring(fgColor.rgb.length - 6)}`
    }
    // 处理ARGB颜色
    else if (fgColor.argb) {
      const color = convertArgbToHex(fgColor.argb)
      if (color) cellStyle.bgcolor = color
    }
  }

  // 处理字体颜色
  if (cell.font && cell.font.color) {
    const fontColor = cell.font.color

    // 处理索引颜色
    if (typeof fontColor.indexed === "number") {
      const indexedColor = indexedColors[fontColor.indexed]
      if (indexedColor) {
        cellStyle.color = `#${indexedColor}`
      }
    }
    // 处理主题颜色
    else if (typeof fontColor.theme === "number") {
      // Excel主题颜色索引映射
      const themeColorMap = {
        0: 1, // 浅色1
        1: 0, // 深色1
        2: 3, // 浅色2
        3: 2, // 深色2
        4: 4, // 强调色1
        5: 5, // 强调色2
        6: 6, // 强调色3
        7: 7, // 强调色4
        8: 8, // 强调色5
        9: 9, // 强调色6
      }

      const mappedIndex =
        themeColorMap[fontColor.theme] !== undefined
          ? themeColorMap[fontColor.theme]
          : fontColor.theme

      if (themeColors.value[mappedIndex]) {
        let color = `#${themeColors.value[mappedIndex]}`

        // 应用色调调整
        if (typeof fontColor.tint === "number" && fontColor.tint !== 0) {
          color = applyTint(color, fontColor.tint)
        }

        cellStyle.color = color
      }
    }
    // 处理RGB颜色
    else if (fontColor.rgb) {
      cellStyle.color = `#${fontColor.rgb.substring(fontColor.rgb.length - 6)}`
    }
    // 处理ARGB颜色
    else if (fontColor.argb) {
      const color = convertArgbToHex(fontColor.argb)
      if (color) cellStyle.color = color
    }
  }

  // 使用样式缓存避免重复
  const styleKey = JSON.stringify(cellStyle)
  if (styleCache.has(styleKey)) {
    return styleCache.get(styleKey)
  }

  // 添加新样式
  styles.push(cellStyle)
  const styleIndex = styles.length - 1
  styleCache.set(styleKey, styleIndex)

  return styleIndex
}

const applyTint = (hexColor, tint) => {
  try {
    // 将十六进制颜色转换为RGB
    const color = tinycolor(hexColor)
    const rgb = color.toRgb()

    // 根据Excel的色调算法调整颜色
    const adjustColor = (value, tint) => {
      let result
      if (tint < 0) {
        // 负色调值，使颜色变暗
        result = value * (1 + tint)
      } else {
        // 正色调值，使颜色变亮
        result = value + (255 - value) * tint
      }
      return Math.max(0, Math.min(255, Math.round(result)))
    }

    // 应用色调到每个RGB通道
    const r = adjustColor(rgb.r, tint)
    const g = adjustColor(rgb.g, tint)
    const b = adjustColor(rgb.b, tint)

    // 返回调整后的颜色
    return tinycolor({ r, g, b }).toHexString()
  } catch (e) {
    return hexColor
  }
}

// 处理列宽
const processColumns = (sheet, sheetData) => {
  const maxCols = Math.min(sheet.columnCount || 26, 50)
  const colWidthCache = new Map()
  const mergedCols = new Set()
  // 收集合并单元格信息
  if (sheet._merges) {
    Object.values(sheet._merges).forEach((merge) => {
      // 记录被合并的列
      for (let col = merge.left; col <= merge.right; col++) {
        mergedCols.add(col - 1)
      }
    })
  }
  // 先收集所有单元格的文本宽度
  sheet.eachRow((row) => {
    for (let colIndex = 0; colIndex < maxCols; colIndex++) {
      try {
        const cell = row.getCell(colIndex + 1)
        if (!cell) continue
        // 安全获取单元格文本
        let cellText = ""
        try {
          if (cell.text !== undefined && cell.text !== null) {
            cellText = String(cell.text)
          } else if (cell.value !== undefined && cell.value !== null) {
            if (typeof cell.value === "object") {
              cellText = cell.value?.richText
                ? cell.value.richText.map((t) => String(t?.text || "")).join("")
                : cell.value?.hyperlink
                ? "[链接]"
                : cell.value?.image
                ? "[图片]"
                : ""
            } else {
              cellText = String(cell.value)
            }
          }
        } catch (e) {
          cellText = ""
        }
        // 计算文本宽度
        if (cellText) {
          // 检查是否是合并单元格的一部分
          const isMerged = Object.values(sheet._merges || {}).some(
            (merge) =>
              row.number >= merge.top &&
              row.number <= merge.bottom &&
              colIndex + 1 >= merge.left &&
              colIndex + 1 <= merge.right
          )
          // 如果是合并单元格，根据合并的列数调整宽度计算
          if (isMerged) {
            const merge = Object.values(sheet._merges || {}).find(
              (m) =>
                row.number >= m.top &&
                row.number <= m.bottom &&
                colIndex + 1 >= m.left &&
                colIndex + 1 <= m.right
            )
            if (merge && colIndex + 1 === merge.left) {
              // 只为合并单元格的第一列计算宽度
              const mergeWidth = merge.right - merge.left + 1
              const textWidth = [...cellText].reduce((width, char) => {
                return width + (/[\u4e00-\u9fa5]/.test(char) ? 2 : 1)
              }, 0)
              // 平均分配到每一列
              const avgWidth = Math.ceil(textWidth / mergeWidth)
              colWidthCache.set(
                colIndex,
                Math.max(colWidthCache.get(colIndex) || 0, avgWidth)
              )
            }
          } else {
            // 普通单元格
            const textWidth = [...cellText].reduce((width, char) => {
              return width + (/[\u4e00-\u9fa5]/.test(char) ? 2 : 1)
            }, 0)
            colWidthCache.set(
              colIndex,
              Math.max(colWidthCache.get(colIndex) || 0, textWidth)
            )
          }
        }
      } catch (e) {
        // 忽略错误
      }
    }
  })

  // 设置列宽
  for (let colIndex = 0; colIndex < maxCols; colIndex++) {
    const width = colWidthCache.get(colIndex)
    if (width) {
      // 根据文本宽度计算列宽，加上一些边距
      const colWidth = Math.min(Math.max(width * 8 + 10, 50), 300)
      sheetData.cols[colIndex] = { width: colWidth }
    }
  }
}

// 将列索引转换为Excel列字母
const columnIndexToLetter = (index) => {
  let temp,
    letter = ""
  while (index >= 0) {
    temp = index % 26
    letter = String.fromCharCode(temp + 65) + letter
    index = (index - temp) / 26 - 1
  }
  return letter
}

// 解析主题颜色
const parseTheme = () => {
  const theme = props.workbook._themes?.theme1
  if (!theme) {
    // Office默认主题颜色
    themeColors.value = [
      "FFFFFF", // 白色 - 浅色1
      "000000", // 黑色 - 深色1
      "EEECE1", // 浅灰 - 浅色2
      "1F497D", // 深灰 - 深色2
      "4F81BD", // 蓝色 - 强调色1
      "C0504D", // 红色 - 强调色2
      "9BBB59", // 绿色 - 强调色3
      "8064A2", // 紫色 - 强调色4
      "4BACC6", // 青色 - 强调色5
      "F79646", // 橙色 - 强调色6
    ]
    return
  }
  try {
    const parser = new DOMParser()
    const doc = parser.parseFromString(theme, "text/xml")
    // 获取颜色方案元素
    const clrScheme = doc.getElementsByTagName("a:clrScheme")[0]
    if (!clrScheme) {
      throw new Error("找不到颜色方案元素")
    }
    // 初始化主题颜色数组
    themeColors.value = []
    const colorElements = Array.from(clrScheme.children)
    // 处理每个颜色元素
    for (const element of colorElements) {
      let colorValue = null
      // 查找颜色定义元素
      const srgbClr = element.getElementsByTagName("a:srgbClr")[0]
      const sysClr = element.getElementsByTagName("a:sysClr")[0]
      if (srgbClr) {
        colorValue = srgbClr.getAttribute("val")
      } else if (sysClr) {
        colorValue =
          sysClr.getAttribute("lastClr") || sysClr.getAttribute("val")
      }
      themeColors.value.push(colorValue || "FFFFFF")
    }
  } catch (error) {
    console.error("解析主题颜色出错:", error)
    themeColors.value = [
      "FFFFFF", // 白色 - 浅色1
      "000000", // 黑色 - 深色1
      "EEECE1", // 浅灰 - 浅色2
      "1F497D", // 深灰 - 深色2
      "4F81BD", // 蓝色 - 强调色1
      "C0504D", // 红色 - 强调色2
      "9BBB59", // 绿色 - 强调色3
      "8064A2", // 紫色 - 强调色4
      "4BACC6", // 青色 - 强调色5
      "F79646", // 橙色 - 强调色6
    ]
  }
}
// 转换ARGB颜色到十六进制
const convertArgbToHex = (argb) => {
  if (!argb || argb.length < 8) return null
  // 去掉透明度通道，只保留RGB部分
  return `#${argb.substring(2)}`
}

// 更新表格
const updateTable = () => {
  parseTheme()
  updateSpreadsheet()
}

// 生命周期钩子
onMounted(() => {
  initSpreadsheet()
})

// 监听属性变化
watch(
  () => props.workbook,
  () => {
    updateTable()
  }
)
</script>

<style>
.spreadsheet-container {
  width: 100%;
  height: 100%;
  position: relative;
}

.spreadsheet-container.loading::before {
  content: "加载中...";
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background: rgba(255, 255, 255, 0.8);
  padding: 10px 20px;
  border-radius: 4px;
  z-index: 100;
}
</style>
