/**
 * plugins/excelExporter.js
 *
 * Xuất Excel từ DataTable với đầy đủ:
 *  - Group header (2 dòng, colspan/rowspan merge)
 *  - Stack split (array → nhiều sub-row, mỗi item 1 dòng)
 *  - splitTemplate, splitExpression, splitField, splitType currency
 *  - Template: FormatNumber, dayjs date, điều kiện row.type===x, Math.abs diff
 *  - Lọc cột action (DebtCheckbox, SvgIcon, modal...)
 *  - Màu header từ headerStyle / tablesetting
 *
 * Không cần cài thêm package — SheetJS load từ CDN lần đầu dùng (lazy).
 */

// ─────────────────────────────────────────────────────────────────────────────
// Import SheetJS từ package đã cài (npm install xlsx)
// ─────────────────────────────────────────────────────────────────────────────
import * as _XLSX from 'xlsx'

async function getXLSX() {
  return _XLSX
}

// ─────────────────────────────────────────────────────────────────────────────
// Helpers
// ─────────────────────────────────────────────────────────────────────────────

function stripHtml(str) {
  if (!str) return ''
  return String(str).replace(/<[^>]*>/g, ' ').replace(/\s+/g, ' ').trim()
}

function fmtCurrency(v) {
  if (v === null || v === undefined || v === '') return ''
  const n = Number(v)
  if (isNaN(n)) return String(v)
  return n.toLocaleString('vi-VN')
}

function fmtDate(raw, fmt = 'DD/MM/YYYY') {
  if (!raw) return ''
  try {
    const d  = new Date(raw)
    const dd = String(d.getDate()).padStart(2, '0')
    const mm = String(d.getMonth() + 1).padStart(2, '0')
    return fmt.replace('DD', dd).replace('MM', mm).replace('YYYY', String(d.getFullYear()))
  } catch { return String(raw) }
}

function resolveSplitTemplate(template, item) {
  return template.replace(/\{(\w+)\}/g, (_, key) => item[key] ?? '')
}

function evalSplitExpression(expression, item) {
  try {
    const expr = expression.replace(/\{(\w+)\}/g, (_, key) => {
      const v = item[key]
      return (v === null || v === undefined) ? 'null' : Number(v)
    })
    // eslint-disable-next-line no-new-func
    return Function('"use strict"; return (' + expr + ')')()
  } catch { return null }
}

// ─────────────────────────────────────────────────────────────────────────────
// Resolve text của 1 item trong stack array
// ─────────────────────────────────────────────────────────────────────────────

function getStackItemText(field, item) {
  if (field.splitExpression) {
    const val = evalSplitExpression(field.splitExpression, item)
    if (val === null || val === undefined) return '—'
    return field.splitType === 'currency' ? fmtCurrency(val) : String(val)
  }
  if (field.splitTemplate) return resolveSplitTemplate(field.splitTemplate, item)
  const val = item[field.splitField]
  if (val === null || val === undefined) return '—'
  return field.splitType === 'currency' ? fmtCurrency(val) : String(val)
}

// ─────────────────────────────────────────────────────────────────────────────
// Resolve text của 1 cell bình thường
// ─────────────────────────────────────────────────────────────────────────────

function getCellText(field, row) {
  if (field.name === '__stt') return row.__stt ?? ''

  if (field.split === 'stack') {
    const arr = row[field.name]
    if (!Array.isArray(arr) || arr.length === 0) return '—'
    // Gom tất cả item thành 1 chuỗi ngăn cách bởi newline
    return arr.map(item => getStackItemText(field, item)).join('\n')
  }

  if (field.template) return evalTemplate(field.template, row)

  if (field.format === 'date' && row[field.name]) return fmtDate(row[field.name])

  if (field.format === 'number' || field.type === 'currency') {
    return row[field.name] !== null && row[field.name] !== undefined
      ? fmtCurrency(row[field.name]) : ''
  }

  return row[field.name] ?? ''
}

function evalTemplate(template, row) {
  // <FormatNumber v-bind="{value: row.xxx}" />
  const fnMatch = template.match(/FormatNumber[^}]*value:\s*row\.(\w+)/)
  if (fnMatch) {
    const v = row[fnMatch[1]]
    return v === null || v === undefined ? '' : fmtCurrency(v)
  }

  // row.type === N ? row.xxx : null
  const condMatch = template.match(/row\.(\w+)\s*===\s*(\d+)\s*\?\s*row\.(\w+)\s*:\s*null/)
  if (condMatch) {
    const v = row[condMatch[1]] === Number(condMatch[2]) ? row[condMatch[3]] : null
    return v === null || v === undefined ? '' : fmtCurrency(v)
  }

  // $dayjs(row.xxx).format('...')
  const djMatch = template.match(/\$dayjs\(row\.(\w+)\)\.format\(['"]([^'"]+)['"]\)/)
  if (djMatch) return fmtDate(row[djMatch[1]], djMatch[2])

  // Math.abs($dayjs().startOf('day').diff(row.xxx, 'day'))
  const diffMatch = template.match(/Math\.abs\(.*\.diff\(row\.(\w+),\s*'day'\)\)/)
  if (diffMatch) {
    try {
      const d = new Date(row[diffMatch[1]]); d.setHours(0, 0, 0, 0)
      const today = new Date(); today.setHours(0, 0, 0, 0)
      return String(Math.abs(Math.round((today - d) / 86400000)))
    } catch { return '' }
  }

  // {{row.xxx}} nội suy đơn giản
  const interpolated = template.replace(/\{\{row\.(\w+)\}\}/g, (_, k) => row[k] ?? '')
  return stripHtml(interpolated)
}

// ─────────────────────────────────────────────────────────────────────────────
// Xây dựng group header row (mirror DataTable.vue groupHeaderRow computed)
// ─────────────────────────────────────────────────────────────────────────────

function buildGroupHeaderRow(fields) {
  const result = []
  let i = 0
  while (i < fields.length) {
    const f = fields[i]
    if (!f.groupHeader) {
      result.push({ label: stripHtml(f.label), colspan: 1, rowspan: 2, isGroup: false })
      i++
    } else {
      let count = 1
      while (i + count < fields.length && fields[i + count].groupHeader === f.groupHeader) count++
      result.push({ label: f.groupHeader, colspan: count, rowspan: 1, isGroup: true })
      i += count
    }
  }
  return result
}

// ─────────────────────────────────────────────────────────────────────────────
// Style helpers
// ─────────────────────────────────────────────────────────────────────────────

function hexFromStyle(headerStyle) {
  const m = (headerStyle || '').match(/background-color:\s*#([0-9a-fA-F]{6})/i)
  return m ? m[1].toUpperCase() : '204853'
}

function thinBorder() {
  const s = { style: 'thin', color: { rgb: 'FFD0D0D0' } }
  return { top: s, bottom: s, left: s, right: s }
}

function headerCellStyle(bgHex, fgHex) {
  return {
    fill:      { patternType: 'solid', fgColor: { rgb: 'FF' + bgHex } },
    font:      { bold: true, color: { rgb: 'FF' + fgHex }, sz: 10, name: 'Arial' },
    alignment: { horizontal: 'center', vertical: 'center', wrapText: true },
    border:    thinBorder(),
  }
}

function dataCellStyle(alignRight, wrapText) {
  return {
    font:      { sz: 10, name: 'Arial' },
    alignment: { horizontal: alignRight ? 'right' : 'left', vertical: 'top', wrapText },
    border:    thinBorder(),
  }
}

// ─────────────────────────────────────────────────────────────────────────────
// Hàm xuất Excel chính
// ─────────────────────────────────────────────────────────────────────────────

async function exportToExcel({ fields, data, tablesetting = [], filename = 'export' }) {
  const XLSX = await getXLSX()

  const hasGroup    = fields.some(f => f.groupHeader)
  const HEADER_ROWS = hasGroup ? 2 : 1

  const fgHex = (tablesetting.find(s => s.code === 'header-font-color')?.detail || '#FFFFFF')
    .replace('#', '').toUpperCase()

  // ── Xây dựng AOA ──────────────────────────────────────────────────────────
  const aoa = []

  if (hasGroup) {
    const groupRow = buildGroupHeaderRow(fields)
    const row1 = []
    const row2 = []
    let colCursor = 0

    groupRow.forEach(col => {
      if (!col.isGroup) {
        row1.push(col.label)
        row2.push('')             // merge về row1 sau
        colCursor++
      } else {
        row1.push(col.label)
        for (let x = 1; x < col.colspan; x++) row1.push('')
        const groupFields = fields.slice(colCursor, colCursor + col.colspan)
        groupFields.forEach(f => row2.push(stripHtml(f.label)))
        colCursor += col.colspan
      }
    })
    aoa.push(row1)
    aoa.push(row2)
  } else {
    aoa.push(fields.map(f => stripHtml(f.label)))
  }

  // ── Dữ liệu ────────────────────────────────────────────────────────────────
  data.forEach((row, idx) => {
    if (row.__stt === undefined) row.__stt = idx + 1

    // Đếm số sub-row cần (bằng max length của các stack field)
    const maxStack = Math.max(1, ...fields.map(f =>
      f.split === 'stack' && Array.isArray(row[f.name]) ? (row[f.name].length || 1) : 1
    ))

    for (let si = 0; si < maxStack; si++) {
      aoa.push(fields.map(f => {
        // Cột stack: lấy item[si]
        if (f.split === 'stack') {
          const arr  = Array.isArray(row[f.name]) ? row[f.name] : []
          const item = arr[si]
          return item ? getStackItemText(f, item) : ''
        }
        // Cột thường: chỉ ghi ở sub-row đầu
        return si === 0 ? String(getCellText(f, row) ?? '') : ''
      }))
    }
  })

  // ── Worksheet ──────────────────────────────────────────────────────────────
  const ws = XLSX.utils.aoa_to_sheet(aoa)

  // ── Merge cells ────────────────────────────────────────────────────────────
  if (hasGroup) {
    const merges    = []
    const groupRow  = buildGroupHeaderRow(fields)
    let c = 0
    groupRow.forEach(col => {
      if (!col.isGroup) {
        merges.push({ s: { r: 0, c }, e: { r: 1, c } })                              // rowspan=2
        c++
      } else {
        if (col.colspan > 1)
          merges.push({ s: { r: 0, c }, e: { r: 0, c: c + col.colspan - 1 } })       // colspan
        c += col.colspan
      }
    })
    ws['!merges'] = merges
  }

  // ── Độ rộng cột ────────────────────────────────────────────────────────────
  ws['!cols'] = fields.map(f => {
    const labelLen = stripHtml(f.label).length
    const minWch   = Math.max(f.minwidth ? f.minwidth / 7 : 10, labelLen + 2)
    const maxWch   = f.maxwidth ? f.maxwidth / 7 : 40
    return { wch: Math.min(minWch, maxWch) }
  })

  // ── Chiều cao dòng header ──────────────────────────────────────────────────
  ws['!rows'] = Array.from({ length: HEADER_ROWS }, () => ({ hpt: 36 }))

  // ── Style từng cell ────────────────────────────────────────────────────────
  const wsRange = XLSX.utils.decode_range(ws['!ref'])
  for (let R = wsRange.s.r; R <= wsRange.e.r; R++) {
    for (let C = wsRange.s.c; C <= wsRange.e.c; C++) {
      const addr = XLSX.utils.encode_cell({ r: R, c: C })
      if (!ws[addr]) ws[addr] = { t: 's', v: '' }
      const f = fields[C]
      if (R < HEADER_ROWS) {
        ws[addr].s = headerCellStyle(hexFromStyle(f?.headerStyle), fgHex)
      } else {
        const isRight = f?.textalign === 'right' || f?.splitType === 'currency'
        const hasStack = f?.split === 'stack'
        ws[addr].s = dataCellStyle(isRight, hasStack)
      }
    }
  }

  // ── Ghi file ───────────────────────────────────────────────────────────────
  const wb = XLSX.utils.book_new()
  XLSX.utils.book_append_sheet(wb, ws, 'Data')
  XLSX.writeFile(wb, `${filename}.xlsx`)
}

// ─────────────────────────────────────────────────────────────────────────────
// Nuxt Plugin
// ─────────────────────────────────────────────────────────────────────────────

export default defineNuxtPlugin(() => {
  return {
    provide: {
      exportTableExcel: exportToExcel,
    },
  }
})