import "server-only"

import ExcelJS from "exceljs"

export type ExcelColumn = {
  header: string
  key: string
  width?: number
}

export type ExcelSheet = {
  name: string
  columns: ExcelColumn[]
  rows: Record<string, unknown>[]
}

export type TemplateColumn = ExcelColumn & {
  note?: string
}

export type TemplateSheet = {
  name: string
  columns: TemplateColumn[]
  sampleRows?: Record<string, unknown>[]
}

export type ParsedSheet = {
  sheetName: string
  rows: Record<string, unknown>[]
}

/**
 * 导出数据到 Excel Buffer
 */
export async function exportToExcel(params: {
  sheets: ExcelSheet[]
}): Promise<Buffer> {
  const workbook = new ExcelJS.Workbook()

  for (const sheet of params.sheets) {
    const worksheet = workbook.addWorksheet(sheet.name, {
      views: [{ state: "frozen", ySplit: 1 }],
    })

    worksheet.columns = sheet.columns.map((col) => ({
      header: col.header,
      key: col.key,
      width: col.width ?? 20,
    }))

    // Header style
    const headerRow = worksheet.getRow(1)
    headerRow.font = { bold: true }
    headerRow.fill = {
      type: "pattern",
      pattern: "solid",
      fgColor: { argb: "FFE0E7FF" },
    }
    headerRow.alignment = { vertical: "middle", horizontal: "left" }

    for (const row of sheet.rows) {
      worksheet.addRow(row)
    }

    worksheet.autoFilter = {
      from: { row: 1, column: 1 },
      to: { row: 1, column: sheet.columns.length },
    }
  }

  const arrayBuffer = await workbook.xlsx.writeBuffer()
  return Buffer.from(arrayBuffer)
}

/**
 * 从 Buffer 解析 Excel
 */
export async function parseExcel(buffer: Buffer): Promise<ParsedSheet[]> {
  const workbook = new ExcelJS.Workbook()
  await workbook.xlsx.load(buffer as unknown as ArrayBuffer)

  const result: ParsedSheet[] = []

  workbook.worksheets.forEach((worksheet) => {
    if (worksheet.rowCount === 0) {
      result.push({ sheetName: worksheet.name, rows: [] })
      return
    }

    const headerRow = worksheet.getRow(1)
    const headers: string[] = []
    const keys: string[] = []

    headerRow.eachCell((cell, colNumber) => {
      const header = String(cell.value ?? "").trim()
      headers.push(header)
      keys.push(header || `column_${colNumber}`)
    })

    const rows: Record<string, unknown>[] = []
    for (let rowNum = 2; rowNum <= worksheet.rowCount; rowNum++) {
      const row = worksheet.getRow(rowNum)
      const record: Record<string, unknown> = {}
      let hasValue = false

      keys.forEach((key, idx) => {
        const cell = row.getCell(idx + 1)
        const value = cell.value
        if (value !== null && value !== undefined && value !== "") {
          record[key] = typeof value === "object" && "text" in value
            ? String((value as { text: string }).text)
            : value
          hasValue = true
        } else {
          record[key] = ""
        }
      })

      if (hasValue) rows.push(record)
    }

    result.push({ sheetName: worksheet.name, rows })
  })

  return result
}

/**
 * 生成导入模板 Buffer
 */
export async function generateTemplate(params: {
  sheets: TemplateSheet[]
}): Promise<Buffer> {
  const workbook = new ExcelJS.Workbook()

  for (const sheet of params.sheets) {
    const worksheet = workbook.addWorksheet(sheet.name)

    worksheet.columns = sheet.columns.map((col) => ({
      header: col.header,
      key: col.key,
      width: col.width ?? 22,
    }))

    const headerRow = worksheet.getRow(1)
    headerRow.font = { bold: true }
    headerRow.fill = {
      type: "pattern",
      pattern: "solid",
      fgColor: { argb: "FFE0E7FF" },
    }

    // Notes row (row 2)
    const noteRow = worksheet.getRow(2)
    sheet.columns.forEach((col, idx) => {
      const cell = noteRow.getCell(idx + 1)
      cell.value = col.note ?? ""
      cell.font = { italic: true, color: { argb: "FF6B7280" } }
    })

    // Sample rows (starting from row 3)
    const sampleRows = sheet.sampleRows ?? []
    sampleRows.forEach((row) => worksheet.addRow(row))

    // Empty row for user input
    if (sampleRows.length === 0) {
      worksheet.addRow({})
    }
  }

  const arrayBuffer = await workbook.xlsx.writeBuffer()
  return Buffer.from(arrayBuffer)
}
