<script lang="ts" setup>
import { reactive, ref, unref } from 'vue'
import * as XLSX from 'xlsx'
import { arrayEquals } from '@/utils/index'
import { generateUuid } from '@/utils/uuid'

const props = defineProps<{
  onSuccess: Function
  headerConfig: string[]
}>()

interface ExcelData {
  header: string[] | null
  content: any[] | null
}

interface ParseResults {
  fileName: string
  results: any[]
  uuid: string
}

const cardStyle = {
  'width': '620px',
  '--n-padding-bottom': '10px',
  '--n-padding-left': '0px',
}
const inputRef = ref(null)
let loading = false
const excelData: ExcelData = { header: null, content: null }
const excelDatas: ParseResults[] = reactive([])

function generateData(content) {
  excelData.header = props.headerConfig
  excelData.content = content
  props.onSuccess && props.onSuccess(excelData)
}

function handleDrop(e) {
  e.stopPropagation()
  e.preventDefault()
  if (loading)
    return
  const files = e.dataTransfer.files
  const rawFiles = Array.from(files)
  // eslint-disable-next-line dot-notation
  const $message = window['$message']

  if (!isExcel(rawFiles)) {
    $message.error('Only supports upload .xlsx, .xls, .csv suffix files')
    return false
  }
  uploadFiles(rawFiles)
  e.stopPropagation()
  e.preventDefault()
}

async function uploadFiles(files) {
  const inputEl: HTMLInputElement | null = unref(inputRef)
  inputEl!.value = ''

  loading = true

  for (const file of files) {
    const fileData = await readFileData(file)
    const message = validate(fileData)
    // TODO
    if (message === undefined || true) {
      const uuid = generateUuid()

      excelDatas.push({
        fileName: file.name,
        results: (fileData as any).results,
        uuid,
      })
    }
  }

  loading = false
}

function commitData() {
  const mergeResults: any[] = []

  if (excelDatas.length === 0)
    return

  excelDatas.forEach((item) => {
    mergeResults.push(...item.results)
  })

  generateData(mergeResults)
}

function validate(fileData) {
  const { header } = fileData

  // 校验表头是否匹配
  const equal = arrayEquals(header, props.headerConfig)

  if (!equal)
    return '表头不匹配'

  // TODO：校验值是否匹配
}

function readFileData(file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader()
    reader.onload = (e) => {
      const data = e.target!.result
      const workbook = XLSX.read(data, { type: 'array' })
      const firstSheetName = workbook.SheetNames[0]
      const worksheet = workbook.Sheets[firstSheetName]
      const header = getHeaderRow(worksheet)
      const results = XLSX.utils.sheet_to_json(worksheet)
      resolve({ header, results })
    }
    reader.readAsArrayBuffer(file)
  })
}

function handleDragover(e) {
  e.stopPropagation()
  e.preventDefault()
  e.dataTransfer.dropEffect = 'copy'
}

function handleUpload() {
  (inputRef.value as any).click()
}

function handleClick(e) {
  const files = e.target.files
  const rawFiles = Array.from(files)
  uploadFiles(rawFiles)
}

function getHeaderRow(sheet) {
  const headers: string[] = []
  const range = XLSX.utils.decode_range(sheet['!ref'])
  let C
  const R = range.s.r
  /* start in the first row */
  for (C = range.s.c; C <= range.e.c; ++C) { /* walk every column in the range */
    const cell = sheet[XLSX.utils.encode_cell({ c: C, r: R })]
    /* find the cell in the first row */
    let hdr = `UNKNOWN ${C}` // <-- replace with your desired default
    if (cell && cell.t)
      hdr = XLSX.utils.format_cell(cell)
    headers.push(hdr)
  }
  return headers
}

function isExcel(files) {
  return files.every((file) => {
    return /\.(xlsx|xls|csv)$/.test(file.name)
  })
}

const show = ref(false)

function showModal() {
  show.value = true
}

function closeModal() {
  show.value = false
}

async function handleSumbit(e: MouseEvent) {
  e.preventDefault()
  commitData()
  closeModal()
}

defineExpose({
  showModal,
})

function removeHandler(id: string) {
  const index = excelDatas.findIndex(item => item.uuid === id)
  excelDatas.splice(index, 1)
}

function afterLeave() {
  excelDatas.length = 0
}
</script>

<template>
  <n-modal v-model:show="show" transform-origin="center" @after-leave="afterLeave">
    <n-card :style="cardStyle" :bordered="false" size="huge" role="dialog" aria-modal="true">
      <div class="wrapper">
        <div class="wrapper-header">
          <span class="wrapper-left">批量导入</span>
          <div class="wrapper-right">
            <div class="wrapper-right-close" @pointerdown="closeModal">
              <div class="wrapper-right-icon" />
            </div>
          </div>
        </div>
        <n-divider />
        <div class="wrapper-content">
          <div class="wrapper-content-dragger" @drop="handleDrop" @dragover="handleDragover" @dragenter="handleDragover">
            <input ref="inputRef" class="excel-upload-input" type="file" accept=".xlsx, .xls,.csv" @change="handleClick">
            <SvgIcon style="margin-top: 30px;" size="45" name="upload" @click="handleUpload" />
            <span style="margin-top: 20px;" class="wrapper-tip1">点击或拖拽审批文件到这里上传</span>
            <span style="margin-top: 15px;margin-bottom: 20px;" class="wrapper-tip2">支持上传格式：.xls .xlsx .csv的文件</span>
          </div>
          <div v-for="(item, index) in excelDatas" :key="index" class="wrapper-content-files">
            <div>{{ item.fileName }}</div>
            <div>
              <SvgIcon
                size="16px" style="display: block; margin-left: auto; cursor: pointer" name="clear"
                @click="removeHandler(item.uuid)"
              />
            </div>
          </div>
        </div>
      </div>
      <template #footer>
        <div class="footer">
          <n-button type="info" @click="handleSumbit">
            确认
          </n-button>
        </div>
      </template>
    </n-card>
  </n-modal>
</template>

<style lang="less" scoped>
.wrapper {
  &-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 10px;
  }

  &-left {
    font-weight: bold;
    font-size: 16px;
  }

  &-right {
    &-close {
      width: 18px;
      height: 18px;
      cursor: pointer;
    }

    &-icon {
      background: #000;
      display: inline-block;
      width: 18px;
      height: 1px;
      transform: rotate(45deg);
      -webkit-transform: rotate(45deg);
      margin-bottom: 8px;

      &:after {
        content: '';
        display: block;
        width: 18px;
        height: 1px;
        background: #000;
        transform: rotate(-90deg);
        -webkit-transform: rotate(-90deg);
      }
    }
  }

  &-content {
    margin-top: 20px;

    &-dragger {
      display: flex;
      flex-direction: column;
      align-items: center;
      border: 1px dashed #1980FF;
      width: 600px;
      margin: 0 auto;
      font-size: 14px;
      font-weight: bold;
      border-radius: 2px;
      text-align: center;
    }

    &-files {
      margin-top: 10px;
      padding: 0px 10px;
      font-size: 14px;
      display: flex;
      justify-content: space-between;
    }
  }

}

.excel-upload-input {
  display: none;
  z-index: -9999;
}

.footer {
  display: flex;
  justify-content: flex-end;
  padding-right: 30px;
}

::v-deep(.n-card.n-card--content-segmented > .n-card__content:not(:first-child)) {
  border: 0px;
}

::v-deep(.n-card > .n-card-header) {
  --n-padding-top: 0px;
  --n-padding-bottom: 12px;
}

::v-deep(.n-divider:not(.n-divider--vertical)) {
  margin-top: 0px;
  margin-bottom: 0px;
}
</style>
