<script setup lang="ts">
import { computed, onMounted, reactive, shallowRef } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import type { UploadFile, UploadUserFile } from 'element-plus'
import { Connection, Delete, Edit, Plus, Upload } from '@element-plus/icons-vue'
import {
  createBank,
  deleteBank,
  exportBank,
  fetchBanks,
  fetchClasses,
  fetchUsers,
  importQuestionRows,
  shareBank,
  updateBank,
  validateQuestionImport,
  validateQuestionRows,
} from '@/api/admin'
import type { QuestionBank, SchoolClass, User } from '@/types/api'

type ImportReportRow = {
  row?: number
  status?: string
  message?: string
  content?: string
  type?: string
}

const loading = shallowRef(false)
const dialogVisible = shallowRef(false)
const uploadVisible = shallowRef(false)
const shareVisible = shallowRef(false)
const selectedBank = shallowRef<QuestionBank | null>(null)
const banks = shallowRef<QuestionBank[]>([])
const users = shallowRef<User[]>([])
const classes = shallowRef<SchoolClass[]>([])
const shareUserIds = shallowRef<number[]>([])
const shareClassIds = shallowRef<number[]>([])
const uploadFiles = shallowRef<UploadUserFile[]>([])
const uploading = shallowRef(false)
const parsed = shallowRef(false)
const importRows = shallowRef<Array<Record<string, unknown>>>([])
const importErrors = shallowRef<Array<{ row: number; message: string }>>([])
const importDuplicates = shallowRef<ImportReportRow[]>([])
const importableCount = shallowRef(0)
const importType = shallowRef('')
const importFilePath = shallowRef('')
const form = reactive({
  id: 0,
  name: '',
  description: '',
  visibility: 'private',
})

const dialogTitle = computed(() => (form.id ? '编辑题库' : '新建题库'))
const visibilityLabels: Record<string, string> = {
  private: '私有',
  public: '公开',
  assigned: '指定用户/班级',
}
const questionTypeLabels: Record<string, string> = {
  single: '单选',
  multiple: '多选',
  judge: '判断',
  blank: '填空',
}
const hasImportReport = computed(() => importDuplicates.value.length > 0 || importErrors.value.length > 0)

async function loadBanks() {
  loading.value = true
  try {
    const response = await fetchBanks()
    banks.value = response.data.items
  } finally {
    loading.value = false
  }
}

function resetForm() {
  form.id = 0
  form.name = ''
  form.description = ''
  form.visibility = 'private'
}

function openCreate() {
  resetForm()
  dialogVisible.value = true
}

function openEdit(row: QuestionBank) {
  form.id = row.id
  form.name = row.name
  form.description = row.description ?? ''
  form.visibility = row.visibility
  dialogVisible.value = true
}

async function submitBank() {
  const payload = {
    name: form.name,
    description: form.description,
    visibility: form.visibility,
  } as Partial<QuestionBank>
  if (form.id) {
    await updateBank(form.id, payload)
    ElMessage.success('题库已更新')
  } else {
    await createBank(payload)
    ElMessage.success('题库已创建')
  }
  dialogVisible.value = false
  resetForm()
  await loadBanks()
}

async function handleUploadChange(file: UploadFile) {
  if (!selectedBank.value || !file.raw || uploading.value) return

  const extension = file.name.split('.').pop()?.toLowerCase()
  if (!extension || !['json', 'xlsx', 'xls', 'csv'].includes(extension)) {
    ElMessage.error('仅支持 JSON、Excel 或 CSV 文件')
    uploadFiles.value = []
    return
  }

  uploading.value = true
  try {
    const response = await validateQuestionImport(selectedBank.value.id, file.raw)
    importRows.value = response.data.rows
    importErrors.value = response.data.errors
    importDuplicates.value = response.data.duplicates
    importableCount.value = response.data.importable_count
    importType.value = response.data.type
    importFilePath.value = response.data.file_path
    parsed.value = true
    if (response.data.valid) {
      ElMessage.success('解析完成，请确认无误后再导入')
    } else {
      ElMessage.warning('解析完成，存在需要修正的题目')
    }
  } finally {
    uploading.value = false
  }
}

function downloadImportExample(format: 'json' | 'csv') {
  const samples = {
    json: JSON.stringify([
      {
        content: 'QuickQuiz 支持哪几种题型？',
        type: 'multiple',
        options: [
          { text: '单选', correct: true },
          { text: '多选', correct: true },
          { text: '问答', correct: false },
        ],
        explanation: '目前支持单选、多选、判断、填空。',
      },
    ], null, 2),
    csv: 'content,type,A,B,C,D,answer,explanation\nQuickQuiz 支持导入题目吗？,single,支持,不支持,,,A,支持 JSON 和 Excel/CSV',
  }
  const blob = new Blob([samples[format]], { type: format === 'json' ? 'application/json' : 'text/csv;charset=utf-8' })
  const link = document.createElement('a')
  link.href = URL.createObjectURL(blob)
  link.download = `quickquiz-import-example.${format}`
  link.click()
  URL.revokeObjectURL(link.href)
}

function openUpload(row: QuestionBank) {
  selectedBank.value = row
  uploadFiles.value = []
  importRows.value = []
  importErrors.value = []
  importDuplicates.value = []
  importableCount.value = 0
  importType.value = ''
  importFilePath.value = ''
  parsed.value = false
  uploadVisible.value = true
}

function abandonImport() {
  uploadVisible.value = false
  uploadFiles.value = []
  importRows.value = []
  importErrors.value = []
  importDuplicates.value = []
  importableCount.value = 0
  importType.value = ''
  importFilePath.value = ''
  parsed.value = false
}

function rowText(row: Record<string, unknown> | undefined) {
  return JSON.stringify(row ?? {}, null, 2)
}

function updateImportRow(index: number, value: string) {
  try {
    importRows.value[index] = JSON.parse(value) as Record<string, unknown>
  } catch {
    ElMessage.warning('当前行不是合法 JSON')
  }
}

async function commitImportRows() {
  if (!selectedBank.value) return
  uploading.value = true
  try {
    const validation = await validateQuestionRows(selectedBank.value.id, { rows: importRows.value })
    importErrors.value = validation.data.errors
    importDuplicates.value = validation.data.duplicates
    importableCount.value = validation.data.importable_count
    importRows.value = validation.data.rows
    if (!validation.data.valid) {
      ElMessage.warning('仍有题目未通过校验，请修正后再导入')
      return
    }

    const response = await importQuestionRows(selectedBank.value.id, {
      rows: importRows.value,
      type: importType.value,
      file_path: importFilePath.value,
    })
    const job = response.data
    ElMessage.success(`导入完成：成功 ${job.success_count} 题，重复 ${job.skipped_count} 题`)
    uploadVisible.value = false
    uploadFiles.value = []
    importRows.value = []
    importErrors.value = []
    importDuplicates.value = []
    importableCount.value = 0
    parsed.value = false
    await loadBanks()
  } finally {
    uploading.value = false
  }
}

function importRowContent(row: Record<string, unknown> | undefined) {
  const value = row?.content ?? row?.questionText ?? row?.['题干'] ?? row?.title ?? ''
  return String(value ?? '')
}

function importRowType(row: Record<string, unknown> | undefined) {
  const value = row?.type ?? row?.questionType ?? row?.['题型'] ?? ''
  return String(value ?? '')
}

function downloadImportReport() {
  const header = ['行号', '类别', '题型', '题干', '说明']
  const duplicateRows = importDuplicates.value.map((item) => [
    item.row ?? '',
    '重复',
    questionTypeLabels[String(item.type ?? '')] ?? item.type ?? '',
    item.content ?? '',
    item.message ?? '',
  ])
  const errorRows = importErrors.value.map((item) => {
    const rawRow = importRows.value[item.row - 1]
    const type = importRowType(rawRow)

    return [
      item.row,
      '错误',
      questionTypeLabels[type] ?? type,
      importRowContent(rawRow),
      item.message,
    ]
  })
  const escape = (value: unknown) => `"${String(value ?? '').replace(/"/g, '""')}"`
  const csv = [header, ...duplicateRows, ...errorRows].map((row) => row.map(escape).join(',')).join('\n')
  const blob = new Blob([`\ufeff${csv}`], { type: 'text/csv;charset=utf-8' })
  const link = document.createElement('a')
  link.href = URL.createObjectURL(blob)
  link.download = `quickquiz-import-check-report-${Date.now()}.csv`
  link.click()
  URL.revokeObjectURL(link.href)
}

async function handleExport(row: QuestionBank) {
  await exportBank(row.id)
  ElMessage.success('题库已导出到 storage/app/exports')
}

async function handleDelete(row: QuestionBank) {
  await ElMessageBox.confirm(`确认删除题库「${row.name}」？`, '删除题库', { type: 'warning' })
  await deleteBank(row.id)
  ElMessage.success('题库已删除')
  await loadBanks()
}

async function openShare(row: QuestionBank) {
  selectedBank.value = row
  shareUserIds.value = []
  shareClassIds.value = []
  const [userResponse, classResponse] = await Promise.all([fetchUsers({ per_page: 100 }), fetchClasses({ per_page: 100 })])
  users.value = userResponse.data.items
  classes.value = classResponse.data.items
  shareVisible.value = true
}

async function saveShare() {
  if (!selectedBank.value) return
  await shareBank(selectedBank.value.id, [
    ...shareUserIds.value.map((id) => ({ type: 'user' as const, id })),
    ...shareClassIds.value.map((id) => ({ type: 'class' as const, id })),
  ])
  ElMessage.success('授权已保存')
  shareVisible.value = false
  await loadBanks()
}

onMounted(loadBanks)
</script>

<template>
  <section class="panel p-5">
    <div class="toolbar mb-4">
      <div class="flex-1">
        <h1 class="page-title">题库管理</h1>
        <p class="muted text-sm mt-1">创建题库，导入 JSON 或 Excel 题目。</p>
      </div>
      <ElButton :icon="Plus" type="primary" @click="openCreate">新建题库</ElButton>
    </div>

    <ElTable v-loading="loading" :data="banks" row-key="id">
      <ElTableColumn prop="name" label="题库名称" min-width="180" />
      <ElTableColumn prop="visibility" label="可见范围" width="140">
        <template #default="{ row }">
          {{ visibilityLabels[row.visibility] || row.visibility }}
        </template>
      </ElTableColumn>
      <ElTableColumn prop="questions_count" label="题量" width="90" />
      <ElTableColumn label="操作" width="400" fixed="right">
        <template #default="{ row }">
          <ElButton :icon="Edit" size="small" @click="openEdit(row)">编辑</ElButton>
          <ElButton
            :icon="Upload"
            size="small"
            @click="openUpload(row)"
          >
            导入
          </ElButton>
          <ElButton :icon="Connection" size="small" @click="openShare(row)">授权</ElButton>
          <ElButton size="small" @click="handleExport(row)">导出</ElButton>
          <ElButton :icon="Delete" size="small" type="danger" plain @click="handleDelete(row)">删除</ElButton>
        </template>
      </ElTableColumn>
    </ElTable>
  </section>

  <ElDialog v-model="dialogVisible" :title="dialogTitle" width="420px">
    <ElForm :model="form" label-position="top">
      <ElFormItem label="名称">
        <ElInput v-model="form.name" />
      </ElFormItem>
      <ElFormItem label="说明">
        <ElInput v-model="form.description" type="textarea" />
      </ElFormItem>
      <ElFormItem label="可见范围">
        <ElSelect v-model="form.visibility" class="w-full">
          <ElOption label="私有" value="private" />
          <ElOption label="公开" value="public" />
          <ElOption label="指定用户/班级" value="assigned" />
        </ElSelect>
      </ElFormItem>
    </ElForm>
    <template #footer>
      <ElButton @click="dialogVisible = false">取消</ElButton>
      <ElButton type="primary" @click="submitBank">保存</ElButton>
    </template>
  </ElDialog>

  <ElDialog v-model="uploadVisible" title="导入题目" width="420px">
    <ElUpload
      v-model:file-list="uploadFiles"
      v-loading="uploading"
      drag
      :auto-upload="false"
      :limit="1"
      :disabled="uploading"
      :on-change="handleUploadChange"
      accept=".json,.xlsx,.xls,.csv"
    >
      <ElIcon class="el-icon--upload"><Upload /></ElIcon>
      <div class="el-upload__text">拖入文件或点击选择</div>
      <template #tip>
        <div class="el-upload__tip">
          <p>先校验再导入；JSON 使用题目数组，Excel/CSV 首行为 content、type、A、B、answer、explanation。</p>
          <ElButton text type="primary" @click.stop="downloadImportExample('json')">下载 JSON 示例</ElButton>
          <ElButton text type="primary" @click.stop="downloadImportExample('csv')">下载 Excel/CSV 示例</ElButton>
        </div>
      </template>
    </ElUpload>
    <section v-if="parsed" class="import-preview">
      <ElAlert
        :type="importErrors.length > 0 ? 'warning' : 'success'"
        :closable="false"
        title="文件已解析，确认前不会写入题库。"
      />
      <div class="import-summary">
        <div>
          <strong>{{ importRows.length }}</strong>
          <span>解析题目</span>
        </div>
        <div>
          <strong>{{ importableCount }}</strong>
          <span>可导入</span>
        </div>
        <div>
          <strong>{{ importDuplicates.length }}</strong>
          <span>重复</span>
        </div>
        <div>
          <strong>{{ importErrors.length }}</strong>
          <span>错误</span>
        </div>
      </div>
      <div v-if="hasImportReport" class="import-report-actions">
        <span>检测到重复或错误题目，可先下载报告核对。</span>
        <ElButton type="primary" plain size="small" @click="downloadImportReport">下载校验报告</ElButton>
      </div>
      <section v-if="importDuplicates.length > 0" class="duplicate-preview">
        <div class="import-section-title">
          <strong>重复题目</strong>
          <span>确认导入时会自动跳过</span>
        </div>
        <ElTable :data="importDuplicates" max-height="180">
          <ElTableColumn prop="row" label="行号" width="72" />
          <ElTableColumn prop="type" label="题型" width="86">
            <template #default="{ row }">
              {{ questionTypeLabels[row.type] || row.type || '-' }}
            </template>
          </ElTableColumn>
          <ElTableColumn prop="content" label="题干" />
        </ElTable>
      </section>
    </section>
    <section v-if="importErrors.length > 0" class="import-errors">
      <ElAlert type="warning" :closable="false" title="以下题目未通过校验，请编辑修正后再确认导入，或放弃本次上传。" />
      <div v-for="error in importErrors" :key="`${error.row}-${error.message}`" class="import-error-row">
        <div class="import-error-head">
          <strong>第 {{ error.row }} 题</strong>
          <span>{{ error.message }}</span>
        </div>
        <ElInput
          :model-value="rowText(importRows[error.row - 1])"
          type="textarea"
          :rows="5"
          @change="updateImportRow(error.row - 1, String($event))"
        />
      </div>
    </section>
    <template #footer>
      <ElButton @click="abandonImport">放弃本次上传</ElButton>
      <ElButton v-if="parsed" type="primary" :loading="uploading" :disabled="importRows.length === 0" @click="commitImportRows">
        确认导入
      </ElButton>
    </template>
  </ElDialog>

  <ElDialog v-model="shareVisible" title="题库授权" width="520px">
    <ElForm label-position="top">
      <ElFormItem label="指定用户">
        <ElSelect v-model="shareUserIds" class="w-full" multiple filterable collapse-tags collapse-tags-tooltip>
          <ElOption v-for="user in users" :key="user.id" :label="`${user.name}（${user.email}）`" :value="user.id" />
        </ElSelect>
      </ElFormItem>
      <ElFormItem label="指定班级">
        <ElSelect v-model="shareClassIds" class="w-full" multiple filterable collapse-tags collapse-tags-tooltip>
          <ElOption v-for="item in classes" :key="item.id" :label="item.name" :value="item.id" />
        </ElSelect>
      </ElFormItem>
    </ElForm>
    <template #footer>
      <ElButton @click="shareVisible = false">取消</ElButton>
      <ElButton type="primary" @click="saveShare">保存授权</ElButton>
    </template>
  </ElDialog>
</template>

<style scoped>
.import-preview {
  display: grid;
  gap: 12px;
  margin-top: 14px;
}

.import-summary {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 8px;
}

.import-summary > div {
  padding: 10px;
  border: 1px solid var(--qq-line);
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.64);
  text-align: center;
}

.import-summary strong {
  display: block;
  color: var(--qq-ink);
  font-size: 20px;
}

.import-summary span,
.import-section-title span {
  color: var(--qq-muted);
  font-size: 12px;
}

.import-report-actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 10px 12px;
  border: 1px solid rgba(217, 119, 6, 0.22);
  border-radius: 8px;
  background: rgba(255, 251, 235, 0.78);
  color: #92400e;
  font-size: 13px;
}

.duplicate-preview {
  display: grid;
  gap: 8px;
}

.import-section-title {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}

.import-errors {
  display: grid;
  gap: 12px;
  margin-top: 14px;
}

.import-error-row {
  display: grid;
  gap: 8px;
}

.import-error-head {
  display: flex;
  align-items: center;
  gap: 8px;
}

.import-error-head span {
  flex: 1;
  color: var(--qq-muted);
  font-size: 13px;
}

.duplicate-content {
  display: inline-block;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
</style>
