<script setup>
import {computed, reactive, ref, watch} from "vue";
import * as XLSX from "xlsx";
import {useQuasar} from "quasar";
import studentApi from "app/src/api/student/student";

const open = defineModel('open')

const func = defineEmits([
  'onClose', 'onOk'
])

const file = ref()

const columnList = [
  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
  'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
]

const tableInfo = reactive({
  sheetIndex: 0,
  studentNumberColumn: 'A',
  studentNameColumn: 'B',
  majorColumn: 'C',
  startRow: 2
})

const quasar = useQuasar()

watch([tableInfo, file], readExcel)

function readExcel() {
  if (file.value === undefined) {
    return
  }

  const fileReader = new FileReader()
  fileReader.readAsArrayBuffer(file.value)

  fileReader.onload = (e) => parseExcel(e.currentTarget.result)

  fileReader.onerror = (e) => {
    console.warn(e)
    quasar.dialog({
      transitionShow: 'fade',
      transitionHide: 'fade',
      title: '啊哈？',
      message: e
    })
  }
}

function indexOfColumn(column) {
  return XLSX.utils.decode_col(column)
}

function checkRow(row, index) {
  if (index < tableInfo.startRow - 1) {
    return false
  }

  function checkNonnull(column) {
    return row[indexOfColumn(column)] !== undefined && row[indexOfColumn(column)] !== null
  }

  return checkNonnull(tableInfo.studentNumberColumn) &&
    checkNonnull(tableInfo.majorColumn) &&
    checkNonnull(tableInfo.studentNameColumn)
}

const parsedStudent = ref([])

function parseExcel(data) {
  const workbook = XLSX.read(data)
  const worksheet = workbook.Sheets[workbook.SheetNames[tableInfo.sheetIndex]]
  const rawData = XLSX.utils.sheet_to_json(worksheet, {header: 1})
  const rows = rawData.filter((r, i) => checkRow(r, i))

  parsedStudent.value = rows.map(row => (
    {
      studentNumber: row[indexOfColumn(tableInfo.studentNumberColumn)],
      studentName: row[indexOfColumn(tableInfo.studentNameColumn)],
      major: row[indexOfColumn(tableInfo.majorColumn)]
    }
  ))

  tablePreview.value = XLSX.utils.sheet_to_html(worksheet)
}

const tablePreview = ref('')

const viewMode = ref('parseResult')

const loading = ref(false)
const progress = ref('0/0')

async function sleep(ms) {
  return await new Promise(r => setTimeout(r, ms));
}

const uploading = ref(false)
const canceled = ref(false)

async function uploadStudents() {
  if (uploading.value) {
    return
  }

  loading.value = true
  const parsedStudentList = parsedStudent.value
  const progressInfo = {
    total: parsedStudentList.length,
    count: 0,
  }

  for (const parsedStudentElement of parsedStudentList) {
    if (canceled.value) {
      break
    }

    try {
      await studentApi.addWithAutoMajor(parsedStudentElement)
      progressInfo.count++
      progress.value = `${progressInfo.count} / ${progressInfo.total}`
    } catch (e) {
      console.warn(e)
    }

    await sleep(200)
  }

  loading.value = false
  open.value = false
  func('onOk')
}
</script>

<template>
  <q-dialog persistent no-esc-dismiss no-shake transition-show="fade" transition-hide="fade"
            v-model="open" full-height full-width maximized>
    <q-layout view="hHh lpR fFf">

      <q-header bordered class="bg-primary text-white">
        <q-toolbar>
          <q-toolbar-title>
            <div class="text-h6">从Excel表格中导入</div>
          </q-toolbar-title>
        </q-toolbar>
      </q-header>

      <q-page-container class="bg-white w-full h-full">
        <div class="flex flex-col gap-4 bg-white p-4 pb-16">
          <p class="text-base">
            在这里可以从Excel表格中导入学生信息<br>
            Excel表格至少需要存在以下信息：『学生学号』、『学生姓名』、『专业名称』<br>
            此处所说的『行号』和『列』均指Excel中行和列的编码（即“A列”，“B列”以及“3行”，“4行”等等，可以在Excel中查看行和列编码），这里的行列编码值与Excel中一致<br>
            专业名称必须与教务处学生信息显示的专业名称完全一致
          </p>
          <div class="flex flex-row gap-4">
            <q-file class="flex-grow" v-model="file" label="选择文件" accept=".xls, .xlsx"/>
            <q-btn class="h-12 w-40 text-base" color="primary" outline @click="readExcel" :disable="file === undefined"
                   label="读取并解析"/>
          </div>

          <div class="flex flex-row max-sm:flex-col gap-8 mt-4">
            <div class="flex flex-row max-sm:flex-col max-sm:content-start content-center gap-4 flex-grow">
              <q-select class="text-base flex-grow max-sm:w-full" outlined :options="columnList"
                        v-model="tableInfo.studentNumberColumn" label="学号列"/>
              <q-select class="text-base flex-grow max-sm:w-full" outlined :options="columnList"
                        v-model="tableInfo.studentNameColumn" label="姓名列"/>
              <q-select class="text-base flex-grow max-sm:w-full" outlined :options="columnList"
                        v-model="tableInfo.majorColumn" label="专业名称列"/>
            </div>

            <div class="bg-gray-200 rounded max-sm:hidden" style="width: 2px"/>

            <q-input class="text-base flex-grow max-sm:w-full" style="max-width: 8rem" outlined type="number"
                     v-model="tableInfo.startRow" label="数据起始行号"/>
          </div>

          <q-separator/>
          <div class="flex flex-row gap-4">
            <q-radio v-model="viewMode" val="parseResult" label="解析结果预览"/>
            <q-radio v-model="viewMode" val="excel" label="原始Excel查看"/>
          </div>
          <q-separator/>

          <transition name="fade" mode="out-in">
            <div v-if="viewMode === 'excel'" class="styled-table" v-html="tablePreview"></div>
            <div v-else class="styled-table">
              <table>
                <tbody>
                <tr>
                  <th>学号</th>
                  <th>姓名</th>
                  <th>专业</th>
                </tr>
                <template v-for="student in parsedStudent" :key="student">
                  <tr>
                    <th>{{ student.studentNumber }}</th>
                    <th>{{ student.studentName }}</th>
                    <th>{{ student.major }}</th>
                  </tr>
                </template>
                </tbody>
              </table>
            </div>
          </transition>
        </div>
      </q-page-container>

      <q-footer bordered class="bg-grey-8 text-white">
        <q-toolbar>
          <q-toolbar-title>
            <div class="flex flex-row">
              <q-btn flat v-close-popup>算了</q-btn>
              <q-btn flat @click="uploadStudents">确认上传</q-btn>
            </div>
          </q-toolbar-title>
        </q-toolbar>
      </q-footer>

    </q-layout>

    <q-inner-loading
      :showing="loading"
      :label="`上传中：${progress}`"
      label-class="text-teal"
      label-style="font-size: 1.1em"
      color="gray"
      class="z-10"
    />
  </q-dialog>
</template>

<style scoped lang="sass">
.fade-enter-active,
.fade-leave-active
  transition: opacity 0.2s ease

.fade-enter-from,
.fade-leave-to
  opacity: 0
</style>

<style lang="sass">

.styled-table
  font-size: 1rem

  table
    width: 100%
    border-collapse: collapse

  table caption
    font-size: 2rem
    font-weight: bold
    margin: .5em 0

  th, td
    border: 1px solid #999
    text-align: center
    padding: .5rem 0

  table thead tr
    background-color: #008c8c
    color: #fff

  table tbody tr:nth-child(odd)
    background-color: #eee

  table tbody tr:hover
    background-color: #ccc

  table tbody tr td:first-child
    color: #f40

  table tfoot tr td
    text-align: right
    padding-right: .5rem
</style>
