<template>
  <section>
    <header class="page-head">
      <div>
        <h2>证书管理</h2>
        <p>支持单张新增、预览、下载、作废、链接重置和批量预生成PDF。</p>
      </div>
      <el-button type="primary" :icon="Plus" @click="openCreateDialog">创建证书</el-button>
    </header>

    <el-dialog v-model="createVisible" title="创建证书" width="920px" destroy-on-close>
      <el-form label-position="top">
        <el-form-item label="证书模板" required>
          <div class="template-choices">
            <button
              v-for="item in templates"
              :key="item.code"
              type="button"
              class="template-choice"
              :class="{ selected: form.template_code === item.code }"
              @click="selectTemplate(item.code)"
            >
              <img :src="item.preview_url" :alt="item.name" />
              <span>
                <strong>{{ item.name }}</strong>
                <small>{{ item.dynamic_fields.join("、") }}</small>
              </span>
            </button>
          </div>
        </el-form-item>

        <div class="create-grid">
          <el-form-item label="学员姓名" required>
            <el-input v-model.trim="form.learner_name" placeholder="请输入证书上的姓名" />
          </el-form-item>
          <el-form-item label="手机号" required>
            <el-input v-model.trim="form.learner_phone" maxlength="18" placeholder="用于匹配或自动创建学员" />
          </el-form-item>
          <el-form-item label="项目" required>
            <el-select v-model="form.project_code" filterable placeholder="选择项目" @change="handleProjectChange">
              <el-option v-for="item in activeProjects" :key="item.code" :label="`${item.code} ${item.name}`" :value="item.code" />
            </el-select>
          </el-form-item>
          <el-form-item v-if="hasTemplateField('course_start_date')" label="课程开始日期" required>
            <el-date-picker v-model="form.course_start_date" type="date" value-format="YYYY-MM-DD" placeholder="选择开始日期" />
          </el-form-item>
          <el-form-item v-if="hasTemplateField('course_end_date')" label="课程结束日期" required>
            <el-date-picker v-model="form.course_end_date" type="date" value-format="YYYY-MM-DD" placeholder="选择结束日期" />
          </el-form-item>
          <el-form-item v-if="hasTemplateField('issue_date')" label="发证日期" required>
            <el-date-picker v-model="form.issue_date" type="date" value-format="YYYY-MM-DD" placeholder="选择发证日期" />
          </el-form-item>
          <el-form-item v-if="hasTemplateField('course_name')" label="课程名称" required>
            <el-input v-model.trim="form.course_name" placeholder="留空时使用项目默认课程名称" />
          </el-form-item>
          <el-form-item v-if="hasTemplateField('stage_name')" label="阶段名称" required>
            <el-input v-model.trim="form.stage_name" placeholder="留空时使用项目默认阶段名称" />
          </el-form-item>
          <el-form-item label="内部备注">
            <el-input v-model.trim="form.remark" placeholder="不会显示在证书上" />
          </el-form-item>
        </div>
        <el-alert
          v-if="selectedTemplate"
          type="info"
          :closable="false"
          :title="`${selectedTemplate.name}将填写：${selectedTemplate.dynamic_fields.join('、')}`"
        />
        <p class="identity-note">手机号已存在时会关联原学员；不存在时将按本次姓名和手机号自动创建学员。</p>
      </el-form>
      <template #footer>
        <el-button @click="createVisible = false">取消</el-button>
        <el-button type="primary" :loading="creating" @click="createCertificate">确认创建</el-button>
      </template>
    </el-dialog>

    <el-card class="panel" shadow="never">
      <div class="toolbar">
        <div class="filter-controls">
          <el-input v-model.trim="keyword" placeholder="按证书编号、名称、项目代码搜索" clearable @keyup.enter="loadCertificates" />
          <el-select v-model="statusValue" clearable placeholder="状态">
            <el-option label="有效" value="valid" />
            <el-option label="已作废" value="voided" />
          </el-select>
          <el-select v-model="pdfStatusValue" clearable placeholder="PDF状态">
            <el-option label="未生成" value="not_generated" />
            <el-option label="已生成" value="generated" />
            <el-option label="已清理" value="cleaned" />
          </el-select>
          <el-select v-model="importBatchId" clearable filterable placeholder="导入批次">
            <el-option v-for="item in importBatches" :key="item.id" :label="`#${item.id} ${item.filename}`" :value="item.id" />
          </el-select>
          <el-button :icon="Search" @click="loadCertificates">搜索</el-button>
        </div>
        <div class="bulk-actions">
          <el-button :icon="Download" @click="exportCertificates">导出</el-button>
          <el-button :icon="Files" :disabled="!importBatchId" :loading="pregenerationStarting" @click="startPregenerationBatch">预生成当前批次</el-button>
          <el-button type="primary" :icon="MagicStick" :disabled="!selectedCertificates.length" :loading="pregenerationStarting" @click="startPregenerationSelected">预生成所选 PDF</el-button>
        </div>
      </div>

      <el-table :data="certificates" border @selection-change="handleSelectionChange">
        <el-table-column type="selection" width="44" />
        <el-table-column prop="certificate_no" label="证书编号" width="180" show-overflow-tooltip />
        <el-table-column prop="learner_name" label="学员姓名" width="100" show-overflow-tooltip />
        <el-table-column prop="learner_phone" label="手机号" width="128" />
        <el-table-column prop="project_code" label="项目" width="72" />
        <el-table-column label="模板" width="150" show-overflow-tooltip>
          <template #default="{ row }">{{ templateName(row.template_code) }}</template>
        </el-table-column>
        <el-table-column prop="certificate_name" label="证书名称" min-width="140" show-overflow-tooltip />
        <el-table-column label="课程时间" width="190">
          <template #default="{ row }">{{ coursePeriodText(row) }}</template>
        </el-table-column>
        <el-table-column prop="issue_date" label="发证日期" width="108" />
        <el-table-column label="PDF" width="92">
          <template #default="{ row }">
            <el-tag :type="row.pdf_status === 'generated' ? 'success' : 'info'">{{ pdfStatusText(row.pdf_status) }}</el-tag>
          </template>
        </el-table-column>
        <el-table-column label="状态" width="80">
          <template #default="{ row }">
            <el-tag :type="row.status === 'valid' ? 'success' : 'danger'">{{ statusText(row.status) }}</el-tag>
          </template>
        </el-table-column>
        <el-table-column label="操作" width="270">
          <template #default="{ row }">
            <div class="table-actions">
              <el-button size="small" @click="previewCertificate(row)">预览</el-button>
              <el-button size="small" :loading="downloadingCertificateId === row.id" @click="downloadCertificate(row)">下载</el-button>
              <el-button size="small" @click="regenerateToken(row)">重置链接</el-button>
              <el-button v-if="row.status === 'valid'" size="small" type="danger" @click="voidCertificate(row)">作废</el-button>
            </div>
          </template>
        </el-table-column>
      </el-table>
    </el-card>

    <el-dialog v-model="previewVisible" title="证书预览" width="680px">
      <el-descriptions v-if="preview" :column="1" border>
        <el-descriptions-item label="证书编号">{{ preview.certificate_no }}</el-descriptions-item>
        <el-descriptions-item label="学员姓名">{{ preview.learner_name }}</el-descriptions-item>
        <el-descriptions-item label="证书名称">{{ preview.certificate_name }}</el-descriptions-item>
        <el-descriptions-item label="项目/课程/阶段">
          {{ preview.project_code }} {{ preview.course_name || "" }} {{ preview.stage_name || "" }}
        </el-descriptions-item>
        <el-descriptions-item label="证书模板">{{ templateName(preview.template_code) }}</el-descriptions-item>
        <el-descriptions-item label="课程时间">{{ coursePeriodText(preview) }}</el-descriptions-item>
        <el-descriptions-item label="发证日期">{{ preview.issue_date }}</el-descriptions-item>
        <el-descriptions-item label="公开链接">
          <a :href="preview.public_url" target="_blank" rel="noreferrer">{{ preview.public_url }}</a>
        </el-descriptions-item>
        <el-descriptions-item label="核验链接">
          <a :href="preview.verify_url" target="_blank" rel="noreferrer">{{ preview.verify_url }}</a>
        </el-descriptions-item>
      </el-descriptions>
    </el-dialog>

    <el-dialog v-model="pregenerationVisible" title="批量预生成PDF" width="560px" @closed="stopPregenerationPolling">
      <div v-if="pregenerationJob" class="pregeneration-panel">
        <el-progress :percentage="pregenerationJob.percent" />
        <dl class="pregeneration-stats">
          <div><dt>总数</dt><dd>{{ pregenerationJob.total }}</dd></div>
          <div><dt>已完成</dt><dd>{{ pregenerationJob.completed }}</dd></div>
          <div><dt>新生成</dt><dd>{{ pregenerationJob.generated }}</dd></div>
          <div><dt>已缓存</dt><dd>{{ pregenerationJob.cached }}</dd></div>
          <div><dt>跳过</dt><dd>{{ pregenerationJob.skipped }}</dd></div>
          <div><dt>失败</dt><dd>{{ pregenerationJob.failed }}</dd></div>
        </dl>
        <p class="progress-note">当前任务按系统设置的最大并发数执行：{{ pregenerationJob.concurrency_limit }}</p>
        <el-alert
          v-if="pregenerationDone"
          :type="pregenerationJob.failed ? 'warning' : 'success'"
          :closable="false"
          :title="pregenerationJob.failed ? '预生成已完成，但有部分失败。' : '预生成已完成。'"
        />
        <ul v-if="pregenerationJob.errors.length" class="error-list">
          <li v-for="item in pregenerationJob.errors" :key="item">{{ item }}</li>
        </ul>
      </div>
    </el-dialog>
  </section>
</template>

<script setup lang="ts">
import { Download, Files, MagicStick, Plus, Search } from "@element-plus/icons-vue";
import { ElLoading, ElMessage, ElMessageBox } from "element-plus";
import { computed, onMounted, onUnmounted, reactive, ref } from "vue";

import {
  http,
  type AdminCertificate,
  type CertificateTemplate,
  type ImportBatch,
  type PdfPregenerationJob,
  type ProjectCourse,
} from "../api";
import { apiErrorMessage, downloadFile } from "../download";

const certificates = ref<AdminCertificate[]>([]);
const projects = ref<ProjectCourse[]>([]);
const templates = ref<CertificateTemplate[]>([]);
const importBatches = ref<ImportBatch[]>([]);
const keyword = ref("");
const statusValue = ref("");
const pdfStatusValue = ref("");
const importBatchId = ref<number | undefined>();
const previewVisible = ref(false);
const preview = ref<any>(null);
const downloadingCertificateId = ref<number | null>(null);
const selectedCertificates = ref<AdminCertificate[]>([]);
const pregenerationStarting = ref(false);
const pregenerationVisible = ref(false);
const pregenerationJob = ref<PdfPregenerationJob | null>(null);
const createVisible = ref(false);
const creating = ref(false);
const templateManuallySelected = ref(false);
let pregenerationTimer: number | null = null;
const form = reactive({
  learner_name: "",
  learner_phone: "",
  project_code: "",
  course_name: "",
  stage_name: "",
  course_start_date: "",
  course_end_date: "",
  issue_date: "",
  template_code: "classic",
  remark: "",
});

const activeProjects = computed(() => projects.value.filter((item) => item.status === "active"));
const selectedTemplate = computed(() => templates.value.find((item) => item.code === form.template_code));

function statusText(status: string) {
  return status === "valid" ? "有效" : "已作废";
}

function pdfStatusText(status: string) {
  return { generated: "已生成", cleaned: "已清理", not_generated: "未生成" }[status] || status;
}

function coursePeriodText(certificate: Pick<AdminCertificate, "course_start_date" | "course_end_date" | "issue_date">) {
  const start = certificate.course_start_date || certificate.issue_date;
  const end = certificate.course_end_date || certificate.issue_date;
  return `${start} 至 ${end}`;
}

function templateName(code: string) {
  return templates.value.find((item) => item.code === code)?.name || code;
}

const pregenerationDone = computed(() => ["completed", "completed_with_errors"].includes(pregenerationJob.value?.status || ""));

async function loadProjects() {
  const { data } = await http.get<ProjectCourse[]>("/admin/projects");
  projects.value = data;
}

async function loadTemplates() {
  const { data } = await http.get<CertificateTemplate[]>("/admin/certificate-templates");
  templates.value = data;
}

async function loadImportBatches() {
  const { data } = await http.get<ImportBatch[]>("/admin/import-batches");
  importBatches.value = data;
}

async function loadCertificates() {
  const { data } = await http.get<AdminCertificate[]>("/admin/certificates", {
    params: {
      keyword: keyword.value || undefined,
      status: statusValue.value || undefined,
      pdf_status: pdfStatusValue.value || undefined,
      import_batch_id: importBatchId.value || undefined,
    },
  });
  certificates.value = data;
}

function handleSelectionChange(rows: AdminCertificate[]) {
  selectedCertificates.value = rows;
}

function resetCreateForm() {
  templateManuallySelected.value = false;
  Object.assign(form, {
    learner_name: "",
    learner_phone: "",
    project_code: "",
    course_name: "",
    stage_name: "",
    course_start_date: "",
    course_end_date: "",
    issue_date: "",
    template_code: "classic",
    remark: "",
  });
}

function selectTemplate(templateCode: string) {
  form.template_code = templateCode;
  templateManuallySelected.value = true;
  if (!hasTemplateField("course_name")) form.course_name = "";
  if (!hasTemplateField("stage_name")) form.stage_name = "";
}

function hasTemplateField(key: string) {
  return !!selectedTemplate.value?.fields.some((field) => field.key === key);
}

function openCreateDialog() {
  resetCreateForm();
  createVisible.value = true;
}

function handleProjectChange(projectCode: string) {
  const project = projects.value.find((item) => item.code === projectCode);
  if (!project) return;
  if (!templateManuallySelected.value) form.template_code = project.default_template_code;
  if (!form.course_name) form.course_name = project.default_course_name || "";
  if (!form.stage_name) form.stage_name = project.default_stage_name || "";
}

async function createCertificate() {
  if (!form.learner_name || !form.learner_phone || !form.project_code) {
    ElMessage.warning("请填写学员姓名、手机号和项目");
    return;
  }
  const fieldValues: Record<string, string> = {
    course_name: form.course_name,
    stage_name: form.stage_name,
    course_start_date: form.course_start_date,
    course_end_date: form.course_end_date,
    issue_date: form.issue_date,
  };
  const missingField = selectedTemplate.value?.fields.find((field) => field.key !== "learner_name" && field.required && !fieldValues[field.key]);
  const project = projects.value.find((item) => item.code === form.project_code);
  const hasProjectDefault = missingField?.key === "course_name" ? project?.default_course_name : missingField?.key === "stage_name" ? project?.default_stage_name : null;
  if (missingField && !hasProjectDefault) {
    ElMessage.warning(`请填写${missingField.label}`);
    return;
  }
  if (form.course_start_date && form.course_end_date && form.course_end_date < form.course_start_date) {
    ElMessage.warning("课程结束日期不能早于课程开始日期");
    return;
  }
  creating.value = true;
  try {
    await http.post("/admin/certificates", {
      learner_name: form.learner_name,
      learner_phone: form.learner_phone,
      project_code: form.project_code,
      course_name: hasTemplateField("course_name") ? form.course_name || null : null,
      stage_name: hasTemplateField("stage_name") ? form.stage_name || null : null,
      course_start_date: form.course_start_date,
      course_end_date: form.course_end_date,
      issue_date: form.issue_date,
      template_code: form.template_code,
      remark: form.remark || null,
    });
    ElMessage.success("证书已创建，学员信息已自动关联");
    createVisible.value = false;
    await loadCertificates();
  } finally {
    creating.value = false;
  }
}

async function previewCertificate(row: AdminCertificate) {
  const { data } = await http.get(`/admin/certificates/${row.id}/preview`);
  preview.value = data;
  previewVisible.value = true;
}

async function downloadCertificate(row: AdminCertificate) {
  downloadingCertificateId.value = row.id;
  const loading = ElLoading.service({
    lock: true,
    text: "当前查询人数较多，请稍后。。。",
    background: "rgba(255, 255, 255, 0.72)",
  });
  try {
    await downloadFile(`/admin/certificates/${row.id}/download`, `${row.certificate_no}.pdf`);
  } catch (error: any) {
    ElMessage.error(await apiErrorMessage(error, "PDF生成失败，请稍后再试"));
  } finally {
    loading.close();
    downloadingCertificateId.value = null;
  }
}

async function voidCertificate(row: AdminCertificate) {
  await ElMessageBox.confirm(`确认作废证书 ${row.certificate_no}？`, "作废证书", { type: "warning" });
  await http.post(`/admin/certificates/${row.id}/void`);
  await loadCertificates();
}

async function regenerateToken(row: AdminCertificate) {
  await ElMessageBox.confirm(`重新生成 ${row.certificate_no} 的直达链接？旧链接会失效。`, "重置链接", { type: "warning" });
  await http.post(`/admin/certificates/${row.id}/token/regenerate`);
  ElMessage.success("直达链接已重置");
}

function exportCertificates() {
  downloadFile("/admin/exports/certificates", "certificates-export.xlsx");
}

async function startPregenerationSelected() {
  const ids = selectedCertificates.value.map((item) => item.id);
  if (!ids.length) {
    ElMessage.warning("请先勾选证书");
    return;
  }
  await startPregeneration({ certificate_ids: ids });
}

async function startPregenerationBatch() {
  if (!importBatchId.value) return;
  await startPregeneration({ import_batch_id: importBatchId.value });
}

async function startPregeneration(payload: { certificate_ids?: number[]; import_batch_id?: number }) {
  pregenerationStarting.value = true;
  try {
    const { data } = await http.post<PdfPregenerationJob>("/admin/certificates/pdf-pregeneration-jobs", payload);
    pregenerationJob.value = data;
    pregenerationVisible.value = true;
    startPregenerationPolling(data.id);
  } catch (error: any) {
    ElMessage.error(await apiErrorMessage(error, "启动PDF预生成失败"));
  } finally {
    pregenerationStarting.value = false;
  }
}

function startPregenerationPolling(jobId: string) {
  stopPregenerationPolling();
  pregenerationTimer = window.setInterval(async () => {
    const { data } = await http.get<PdfPregenerationJob>(`/admin/certificates/pdf-pregeneration-jobs/${jobId}`);
    pregenerationJob.value = data;
    if (["completed", "completed_with_errors"].includes(data.status)) {
      stopPregenerationPolling();
      await loadCertificates();
    }
  }, 1000);
}

function stopPregenerationPolling() {
  if (pregenerationTimer) {
    clearInterval(pregenerationTimer);
    pregenerationTimer = null;
  }
}

onMounted(async () => {
  await Promise.all([loadProjects(), loadTemplates(), loadImportBatches(), loadCertificates()]);
});

onUnmounted(stopPregenerationPolling);
</script>

<style scoped>
.page-head,
.toolbar {
  display: flex;
  gap: 12px;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 16px;
}

.page-head p {
  margin: 6px 0 0;
  color: #64748b;
}

.panel {
  margin-bottom: 16px;
  border-radius: 8px;
}

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

.template-choices {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  width: 100%;
}

.template-choice {
  display: grid;
  grid-template-columns: 148px minmax(0, 1fr);
  align-items: center;
  gap: 14px;
  min-height: 112px;
  padding: 10px;
  border: 1px solid var(--app-border);
  border-radius: 8px;
  background: #fff;
  color: var(--app-text);
  text-align: left;
  cursor: pointer;
}

.template-choice:hover,
.template-choice.selected {
  border-color: var(--app-primary);
  box-shadow: 0 0 0 3px rgba(22, 129, 126, 0.1);
}

.template-choice img {
  width: 148px;
  aspect-ratio: 1.36;
  object-fit: contain;
  border: 1px solid #edf2f4;
  background: #f8fafb;
}

.template-choice span {
  display: grid;
  gap: 8px;
}

.template-choice strong {
  font-size: 15px;
}

.identity-note {
  margin: 12px 0 0;
  color: var(--app-text-secondary);
  font-size: 13px;
}

.template-choice small {
  color: var(--app-muted);
  line-height: 1.55;
}

.create-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0 14px;
}

.create-grid :deep(.el-select),
.create-grid :deep(.el-date-editor) {
  width: 100%;
}

.toolbar {
  align-items: flex-start;
  flex-wrap: wrap;
  justify-content: space-between;
  padding-bottom: 16px;
  border-bottom: 1px solid #edf1f3;
}

.filter-controls,
.bulk-actions {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

.filter-controls {
  flex: 1 1 660px;
}

.bulk-actions {
  justify-content: flex-end;
}

.filter-controls .el-input {
  flex: 1 1 260px;
  max-width: 340px;
}

.filter-controls .el-select {
  width: 170px;
}

.form-tip {
  font-size: 12px;
  color: #94a3b8;
  line-height: 1.6;
  margin-top: 4px;
}

.table-actions {
  display: flex;
  gap: 8px;
  flex-wrap: nowrap;
}

.table-actions :deep(.el-button + .el-button) {
  margin-left: 0;
}

.pregeneration-panel {
  display: grid;
  gap: 16px;
}

.pregeneration-stats {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 8px;
  margin: 0;
}

.pregeneration-stats div {
  border: 1px solid #e2edf0;
  border-radius: 8px;
  padding: 10px;
  text-align: center;
}

.pregeneration-stats dt {
  color: #64748b;
  font-size: 12px;
}

.pregeneration-stats dd {
  margin: 4px 0 0;
  font-size: 18px;
  font-weight: 700;
}

.progress-note {
  margin: 0;
  color: #64748b;
}

.error-list {
  margin: 0;
  padding-left: 18px;
  color: #991b1b;
}

@media (max-width: 760px) {
  .template-choices,
  .create-grid {
    grid-template-columns: 1fr;
  }

  .filter-controls,
  .bulk-actions {
    width: 100%;
  }

  .filter-controls .el-input,
  .filter-controls .el-select,
  .bulk-actions .el-button {
    width: 100%;
    max-width: none;
    margin: 0;
  }
}
</style>
