<script setup lang="ts">
import { computed, onMounted, reactive, ref } from 'vue'
import { Download, Plus, Refresh, Search } from '@element-plus/icons-vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import http, { apiErrorMessage } from '../api/http'
import { useAuthStore } from '../stores/auth'

type DocumentType = 'Transcript' | 'StudentStatusCertificate'
type DocumentStatus = 'Valid' | 'Invalidated' | 'Superseded'

interface OfficialDocumentRow {
  id: string
  documentNumber: string
  type: DocumentType
  status: DocumentStatus
  studentId: string
  studentNumber: string
  studentName: string
  collegeName: string
  purpose?: string
  issuedAt: string
  issuedByName: string
  invalidatedAt?: string
  invalidationReason?: string
  reissuedFromDocumentId?: string
  downloadCount: number
  lastDownloadedAt?: string
}

interface StudentOption {
  id: string
  studentNumber: string
  name: string
  status: string
  className: string
  majorName: string
  collegeName: string
}

const auth = useAuthStore()
const isManager = computed(() =>
  auth.user?.roles.some((role) => ['SuperAdmin', 'AcademicAdmin', 'CollegeAdmin'].includes(role)),
)
const loading = ref(false)
const issuing = ref(false)
const documents = ref<OfficialDocumentRow[]>([])
const students = ref<StudentOption[]>([])
const issueDialog = ref(false)
const historyDrawer = ref(false)
const historyLoading = ref(false)
const downloadHistory = ref<any[]>([])
const selectedDocument = ref<OfficialDocumentRow>()
const filters = reactive<{ type?: DocumentType; status?: DocumentStatus }>({})
const issueForm = reactive<{ studentId: string; type: DocumentType; purpose: string }>({
  studentId: '',
  type: 'Transcript',
  purpose: '',
})

const typeLabels: Record<DocumentType, string> = {
  Transcript: '官方电子成绩单',
  StudentStatusCertificate: '学籍状态证明',
}
const statusLabels: Record<DocumentStatus, string> = {
  Valid: '有效',
  Invalidated: '已失效',
  Superseded: '已重签',
}

async function load() {
  loading.value = true
  try {
    const { data } = await http.get('/official-documents', { params: filters })
    documents.value = data
  } catch (error) {
    ElMessage.error(apiErrorMessage(error))
  } finally {
    loading.value = false
  }
}

async function loadStudents(keyword = '') {
  if (!isManager.value) return
  try {
    const { data } = await http.get('/official-documents/students/options', {
      params: { keyword: keyword || undefined },
    })
    students.value = data
  } catch (error) {
    ElMessage.error(apiErrorMessage(error))
  }
}

async function openIssue() {
  issueForm.studentId = ''
  issueForm.type = 'Transcript'
  issueForm.purpose = ''
  issueDialog.value = true
  if (isManager.value) await loadStudents()
}

async function issue() {
  if (isManager.value && !issueForm.studentId) {
    ElMessage.warning('请选择学生。')
    return
  }
  issuing.value = true
  try {
    const response = isManager.value
      ? await http.post('/official-documents', issueForm)
      : await http.post('/official-documents/mine', {
          type: issueForm.type,
          purpose: issueForm.purpose,
        })
    issueDialog.value = false
    ElMessage.success(
      response.data?.reused
        ? '已为你保留刚申请的同类有效凭证。'
        : isManager.value
          ? '官方凭证已签发。'
          : '电子凭证已生成，可在列表中下载。',
    )
    await load()
  } catch (error) {
    ElMessage.error(apiErrorMessage(error))
  } finally {
    issuing.value = false
  }
}

async function download(row: OfficialDocumentRow) {
  try {
    const response = await http.get(`/official-documents/${row.id}/download`, {
      responseType: 'blob',
      timeout: 30000,
    })
    const url = URL.createObjectURL(response.data)
    const anchor = document.createElement('a')
    anchor.href = url
    anchor.download = `${row.documentNumber}.pdf`
    anchor.click()
    URL.revokeObjectURL(url)
    await load()
  } catch (error) {
    ElMessage.error(apiErrorMessage(error))
  }
}

async function invalidate(row: OfficialDocumentRow) {
  try {
    const { value } = await ElMessageBox.prompt(
      '失效后学生不能再下载，但已下载文件仍可扫码看到“已失效”。请输入原因。',
      '确认失效',
      { inputPattern: /^.{2,500}$/, inputErrorMessage: '原因需为 2-500 个字符', confirmButtonText: '确认失效' },
    )
    await http.post(`/official-documents/${row.id}/invalidate`, { reason: value })
    ElMessage.success('凭证已失效。')
    await load()
  } catch (error: any) {
    if (error === 'cancel' || error === 'close') return
    ElMessage.error(apiErrorMessage(error))
  }
}

async function reissue(row: OfficialDocumentRow) {
  try {
    const { value } = await ElMessageBox.prompt(
      '系统会冻结原凭证并按当前正式数据生成新编号和新二维码。请输入重签原因。',
      '重签凭证',
      { inputPattern: /^.{2,500}$/, inputErrorMessage: '原因需为 2-500 个字符', confirmButtonText: '确认重签' },
    )
    await http.post(`/official-documents/${row.id}/reissue`, { reason: value })
    ElMessage.success('新凭证已签发，原凭证已标记为被替代。')
    await load()
  } catch (error: any) {
    if (error === 'cancel' || error === 'close') return
    ElMessage.error(apiErrorMessage(error))
  }
}

async function showHistory(row: OfficialDocumentRow) {
  selectedDocument.value = row
  historyDrawer.value = true
  historyLoading.value = true
  try {
    const { data } = await http.get(`/official-documents/${row.id}/downloads`)
    downloadHistory.value = data
  } catch (error) {
    ElMessage.error(apiErrorMessage(error))
  } finally {
    historyLoading.value = false
  }
}

function formatTime(value?: string) {
  return value ? new Date(value).toLocaleString('zh-CN', { hour12: false }) : '—'
}

function statusTagType(status: DocumentStatus) {
  return status === 'Valid' ? 'success' : status === 'Superseded' ? 'warning' : 'danger'
}

onMounted(load)
</script>

<template>
  <div class="document-page">
    <header class="document-hero">
      <div>
        <span>OFFICIAL DOCUMENT SERVICE</span>
        <h2>{{ isManager ? '官方凭证签发中心' : '电子成绩单与证明' }}</h2>
        <p>{{ isManager ? '服务端固化签发快照和 PDF，凭证编号唯一，二维码可公开验真。' : '在线申请后即时生成，可下载 PDF，并通过二维码公开验真。' }}</p>
      </div>
      <el-button type="primary" :icon="Plus" @click="openIssue">
        {{ isManager ? '签发新凭证' : '申请电子凭证' }}
      </el-button>
    </header>

    <section class="trust-strip">
      <div><b>唯一编号</b><span>每次签发独立编号</span></div>
      <div><b>二维码验真</b><span>实时显示有效状态</span></div>
      <div><b>下载留痕</b><span>时间、账号与来源可追溯</span></div>
      <div><b>失效与重签</b><span>旧凭证保留完整链路</span></div>
    </section>

    <section class="document-toolbar">
      <el-select v-model="filters.type" clearable placeholder="全部凭证类型" @change="load">
        <el-option v-for="(label, value) in typeLabels" :key="value" :label="label" :value="value" />
      </el-select>
      <el-select v-model="filters.status" clearable placeholder="全部状态" @change="load">
        <el-option v-for="(label, value) in statusLabels" :key="value" :label="label" :value="value" />
      </el-select>
      <el-button :icon="Refresh" @click="load">刷新</el-button>
      <span>共 {{ documents.length }} 份凭证</span>
    </section>

    <section class="document-list" v-loading="loading">
      <article v-for="row in documents" :key="row.id" class="document-card">
        <div class="document-mark" :class="row.type === 'Transcript' ? 'transcript' : 'certificate'">
          <span>{{ row.type === 'Transcript' ? 'TR' : 'SC' }}</span>
          <small>PDF</small>
        </div>
        <div class="document-main">
          <div class="document-title">
            <div>
              <span>{{ typeLabels[row.type] }}</span>
              <h3>{{ row.documentNumber }}</h3>
            </div>
            <el-tag :type="statusTagType(row.status)" effect="plain">{{ statusLabels[row.status] }}</el-tag>
          </div>
          <p class="student-line">
            <b>{{ row.studentName }}</b>
            <span>{{ row.studentNumber }} · {{ row.collegeName }}</span>
          </p>
          <p class="document-meta">
            签发于 {{ formatTime(row.issuedAt) }} · {{ row.issuedByName }}
            <template v-if="row.purpose"> · 用途：{{ row.purpose }}</template>
          </p>
          <el-alert
            v-if="row.status !== 'Valid'"
            :title="`${statusLabels[row.status]}：${row.invalidationReason || '未填写原因'}`"
            type="warning"
            :closable="false"
          />
        </div>
        <div class="document-actions">
          <el-button v-if="row.status === 'Valid'" type="primary" :icon="Download" @click="download(row)">下载 PDF</el-button>
          <el-button v-if="isManager" :icon="Search" @click="showHistory(row)">下载记录（{{ row.downloadCount }}）</el-button>
          <el-button v-if="isManager && row.status === 'Valid'" type="danger" plain @click="invalidate(row)">设为失效</el-button>
          <el-button v-if="isManager && row.status !== 'Superseded'" type="warning" plain @click="reissue(row)">重签</el-button>
        </div>
      </article>
      <el-empty
        v-if="!documents.length"
        :description="isManager ? '暂无符合条件的官方凭证' : '暂无电子凭证，可点击上方按钮在线申请'"
      />
    </section>

    <el-dialog v-model="issueDialog" :title="isManager ? '签发官方凭证' : '申请电子凭证'" width="620px">
      <el-alert
        :title="isManager
          ? '签发后将固化当前正式数据；后续数据修改不会悄悄改变已签发文件。'
          : '系统将按你的学籍档案即时生成；成绩单仅包含已正式发布的成绩，5 分钟内重复申请同类型、同用途凭证将复用已有文件。'"
        type="info"
        :closable="false"
      />
      <el-form label-position="top" class="issue-form">
        <el-form-item v-if="isManager" label="学生" required>
          <el-select
            v-model="issueForm.studentId"
            filterable
            remote
            :remote-method="loadStudents"
            placeholder="按姓名或学号搜索"
            style="width: 100%"
          >
            <el-option
              v-for="student in students"
              :key="student.id"
              :value="student.id"
              :label="`${student.studentNumber} · ${student.name}`"
            >
              <div class="student-option">
                <b>{{ student.studentNumber }} · {{ student.name }}</b>
                <span>{{ student.collegeName }} · {{ student.majorName }} · {{ student.className }}</span>
              </div>
            </el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="凭证类型" required>
          <el-radio-group v-model="issueForm.type">
            <el-radio-button value="Transcript">官方电子成绩单</el-radio-button>
            <el-radio-button value="StudentStatusCertificate">学籍状态证明</el-radio-button>
          </el-radio-group>
        </el-form-item>
        <el-form-item label="用途（可选）">
          <el-input v-model="issueForm.purpose" maxlength="200" show-word-limit placeholder="例如：升学申请、实习材料" />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="issueDialog = false">取消</el-button>
        <el-button type="primary" :loading="issuing" @click="issue">
          {{ isManager ? '确认签发' : '提交申请' }}
        </el-button>
      </template>
    </el-dialog>

    <el-drawer v-model="historyDrawer" title="凭证下载记录" size="560px">
      <p class="drawer-number">{{ selectedDocument?.documentNumber }}</p>
      <el-table :data="downloadHistory" v-loading="historyLoading">
        <el-table-column label="下载人" prop="downloadedByName" min-width="110" />
        <el-table-column label="下载时间" min-width="165">
          <template #default="{ row }">{{ formatTime(row.createdAt) }}</template>
        </el-table-column>
        <el-table-column label="来源 IP" prop="ipAddress" min-width="130" />
      </el-table>
      <el-empty v-if="!historyLoading && !downloadHistory.length" description="尚无下载记录" />
    </el-drawer>
  </div>
</template>

<style scoped>
.document-page { display: grid; gap: 18px; }
.document-hero { display: flex; align-items: end; justify-content: space-between; gap: 24px; padding: 26px 28px; border-radius: 12px; color: #f4fbf8; background: linear-gradient(120deg, #173b3a, #245e55 68%, #33746a); box-shadow: 0 14px 34px rgba(25, 65, 60, .16); }
.document-hero span { font: 650 10px/1.2 Consolas, monospace; letter-spacing: .18em; opacity: .72; }
.document-hero h2 { margin: 8px 0 5px; font: 700 27px/1.25 Georgia, "Noto Serif SC", serif; }
.document-hero p { margin: 0; color: rgba(244, 251, 248, .74); font-size: 13px; }
.trust-strip { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1px; overflow: hidden; border: 1px solid #dce7e4; border-radius: 10px; background: #dce7e4; }
.trust-strip div { display: grid; gap: 3px; padding: 14px 18px; background: #f8fbfa; }
.trust-strip b { color: #244d48; font-size: 13px; }
.trust-strip span { color: #71807e; font-size: 11px; }
.document-toolbar { display: flex; align-items: center; gap: 10px; }
.document-toolbar .el-select { width: 180px; }
.document-toolbar > span { margin-left: auto; color: #7b8785; font-size: 12px; }
.document-list { display: grid; gap: 12px; min-height: 180px; }
.document-card { display: grid; grid-template-columns: 74px minmax(0, 1fr) auto; gap: 18px; align-items: center; padding: 18px; border: 1px solid #e0e7e5; border-radius: 10px; background: white; }
.document-mark { display: grid; place-content: center; width: 62px; height: 76px; border-radius: 5px 5px 12px 5px; color: white; background: #245e55; box-shadow: 0 8px 18px rgba(36, 94, 85, .18); }
.document-mark.certificate { background: #6b5541; }
.document-mark span { font: 800 18px/1 Consolas, monospace; letter-spacing: .1em; }
.document-mark small { margin-top: 7px; text-align: center; font: 700 8px/1 Consolas, monospace; opacity: .68; }
.document-main { min-width: 0; }
.document-title { display: flex; align-items: start; justify-content: space-between; gap: 12px; }
.document-title span { color: #687774; font-size: 11px; }
.document-title h3 { margin: 4px 0 0; overflow: hidden; color: #263d3a; font: 700 15px/1.3 Consolas, monospace; text-overflow: ellipsis; }
.student-line { display: flex; gap: 9px; align-items: baseline; margin: 11px 0 4px; }
.student-line b { color: #263d3a; }
.student-line span, .document-meta { color: #77827f; font-size: 12px; }
.document-meta { margin: 0 0 8px; }
.document-actions { display: flex; flex-direction: column; gap: 7px; min-width: 150px; }
.issue-form { margin-top: 18px; }
.student-option { display: grid; line-height: 1.3; }
.student-option span { color: #8a9693; font-size: 11px; }
.drawer-number { margin: -8px 0 18px; color: #667572; font: 600 12px Consolas, monospace; }
@media (max-width: 760px) {
  .document-hero { align-items: stretch; flex-direction: column; padding: 22px; }
  .trust-strip { grid-template-columns: 1fr 1fr; }
  .document-toolbar { align-items: stretch; flex-wrap: wrap; }
  .document-toolbar .el-select { width: calc(50% - 5px); }
  .document-toolbar > span { width: 100%; margin-left: 0; }
  .document-card { grid-template-columns: 54px minmax(0, 1fr); align-items: start; padding: 14px; }
  .document-mark { width: 50px; height: 62px; }
  .document-actions { grid-column: 1 / -1; display: grid; grid-template-columns: 1fr 1fr; }
  .student-line { align-items: start; flex-direction: column; gap: 2px; }
}
</style>
