<script setup>
import { computed, onMounted, reactive, ref, watch } from 'vue';
import { useRouter } from 'vue-router';
import PortalShell from '@/layouts/PortalShell.vue';
import PageState from '@/components/common/PageState.vue';
import StatusBadge from '@/components/common/StatusBadge.vue';
import ProfileFields from '@/components/common/ProfileFields.vue';
import AccountSecurity from '@/components/common/AccountSecurity.vue';
import { api } from '@/lib/api';
import { dateRange, formatDate, money, passPolicyText } from '@/lib/format';
import { statusLabel } from '@/lib/business-labels';
import { sessionStore } from '@/stores/session';
import { uiStore } from '@/stores/ui';

const props = defineProps({ page: { type: String, required: true } });
const router = useRouter();
const loading = ref(true);
const error = ref('');
const data = ref({});
const selectedSubjects = reactive({});
const appealReasons = reactive({});
const preferenceDrafts = reactive({});
const profileForm = reactive({});
const passwordForm = reactive({ currentPassword: '', newPassword: '', confirmPassword: '' });
const saving = ref(false);

const meta = computed(() => ({
  dashboard: ['总览', '查看资料、报名、准考证与成绩状态。'], profile: ['个人资料', '维护实名、学籍和联系信息。'],
  exams: ['考试报名', '在开放时间内选择考试和报考科目。'], registrations: ['我的报名', '查看考试、科目和审核进度。'],
  admit: ['准考证', '在规定时间内下载已经生成的准考证。'], results: ['成绩查询', '查看正式发布的成绩并申请复议。'],
  admissions: ['志愿填报与录取', '填报本人志愿并查看投档与录取进度。'], notices: ['通知公告', '查看与考试相关的最新通知。'],
  security: ['账户安全', '修改登录密码并管理二次验证。'], onboarding: ['首次登录', '完成密码更新和个人资料建档。']
}[props.page] || ['考生中心', '办理个人考试事项。']));

const endpoint = computed(() => ({
  dashboard: 'dashboard', profile: 'profile', exams: 'exams', registrations: 'registrations', admit: 'registrations',
  results: 'results', admissions: 'admissions', notices: 'notices'
}[props.page]));

const registrations = computed(() => data.value.registrations || (Array.isArray(data.value) ? data.value : []));
const groupedResults = computed(() => Object.values((data.value.results || []).reduce((groups, item) => {
  (groups[item.examId] ||= []).push(item); return groups;
}, {})));
const classesForSchool = computed(() => (data.value.classes || []).filter(item => item.schoolId === profileForm.schoolId));

async function load() {
  loading.value = true; error.value = '';
  try {
    if (props.page === 'onboarding') {
      if (sessionStore.state.user?.mustChangePassword) data.value = { stage: 'password' };
      else data.value = await api('/api/candidate/profile');
    } else if (props.page === 'security') data.value = await api('/api/auth/totp');
    else data.value = await api(`/api/candidate/${endpoint.value}`);
    hydrate();
  } catch (requestError) { error.value = requestError.message; }
  finally { loading.value = false; }
}

function hydrate() {
  const profile = data.value.profile || {};
  Object.keys(profileForm).forEach(key => delete profileForm[key]);
  Object.assign(profileForm, profile, { idNumber: String(profile.idNumber || '').startsWith('PENDING-') ? '' : profile.idNumber || '' });
  for (const exam of data.value.exams || []) selectedSubjects[exam.id] = [...(exam.registration?.subjectIds || [])];
  for (const item of data.value.admissions || []) {
    const existing = item.preference?.payload?.choices || [];
    const indicator = existing.find(choice => choice.preferenceType === 'indicator') || { schoolId: '', categoryCode: '', preferenceType: 'indicator' };
    const general = existing.filter(choice => choice.preferenceType !== 'indicator');
    preferenceDrafts[item.examId] = [indicator, ...Array.from({ length: Number(item.payload?.maxChoices || 5) }, (_, index) => ({
      schoolId: general[index]?.schoolId || '', categoryCode: general[index]?.categoryCode || '', preferenceType: 'general'
    }))];
  }
}

async function changePassword(onboarding = false) {
  if (passwordForm.newPassword !== passwordForm.confirmPassword) { error.value = '两次输入的新密码不一致'; return; }
  saving.value = true; error.value = '';
  try {
    await api('/api/auth/change-password', { method: 'POST', body: passwordForm });
    Object.assign(passwordForm, { currentPassword: '', newPassword: '', confirmPassword: '' });
    await sessionStore.refreshSession();
    uiStore.notify('密码修改成功', onboarding ? '请继续补全个人资料' : '下次登录请使用新密码');
    if (onboarding) await load();
  } catch (requestError) { error.value = requestError.message; }
  finally { saving.value = false; }
}

async function saveProfile(onboarding = false) {
  saving.value = true; error.value = '';
  try {
    const fields = ['name','gender','idNumber','birthDate','nativePlace','ethnicity','schoolId','classId','provinceCode','cityCode','districtCode','phone','email','address','postalCode','guardianName','guardianPhone','emergencyContact','emergencyPhone','specialtyCategory','specialtyType','specialtyCertificate','policyEligibility'];
    const body = Object.fromEntries(fields.map(key => [key, profileForm[key] ?? '']));
    const response = await api('/api/candidate/profile', { method: 'PUT', body });
    sessionStore.state.profile = response.profile;
    await sessionStore.refreshSession();
    uiStore.notify('资料已提交', '管理员审核后会更新状态');
    if (onboarding) await router.replace('/candidate/dashboard'); else await load();
  } catch (requestError) { error.value = requestError.message; }
  finally { saving.value = false; }
}

async function registerExam(exam) {
  const subjectIds = selectedSubjects[exam.id] || [];
  if (!subjectIds.length) { uiStore.notify('请选择科目', '至少选择一个报考科目', 'warning'); return; }
  saving.value = true;
  try {
    await api('/api/candidate/registrations', { method: 'POST', body: { examId: exam.id, subjectIds } });
    uiStore.notify('报名已提交', `已选择 ${subjectIds.length} 个科目`);
    await load();
  } catch (requestError) { error.value = requestError.message; }
  finally { saving.value = false; }
}

async function submitAppeal(result) {
  const reason = String(appealReasons[result.id] || '').trim();
  if (reason.length < 5) { uiStore.notify('请补充复议理由', '至少填写 5 个字', 'warning'); return; }
  try {
    await api(`/api/candidate/results/${result.id}/appeals`, { method: 'POST', body: { reason } });
    appealReasons[result.id] = '';
    uiStore.notify('成绩复议已提交', '可在本页查看处理进度');
    await load();
  } catch (requestError) { error.value = requestError.message; }
}

function availablePlans(item, type) {
  return (item.plans || []).filter(plan => (plan.categories || []).some(category => (category.preferenceTypes || []).includes(type)));
}
function categoriesFor(item, choice) {
  const plan = (item.plans || []).find(row => row.schoolId === choice.schoolId);
  return (plan?.categories || []).filter(category => (category.preferenceTypes || []).includes(choice.preferenceType));
}
async function savePreferences(item) {
  const choices = (preferenceDrafts[item.examId] || []).filter(choice => choice.schoolId && choice.categoryCode);
  try {
    const response = await api(`/api/candidate/admissions/${item.examId}/preferences`, { method: 'PUT', body: { choices } });
    uiStore.notify(response.locked ? '志愿已保存并锁定' : '志愿已保存', response.locked ? '提交次数已达到上限' : `还可提交 ${response.remainingSubmissions} 次`);
    await load();
  } catch (requestError) { error.value = requestError.message; }
}

function downloadAdmit(id) { window.location.href = `/api/candidate/registrations/${id}/admit-card`; }
async function downloadScore(items) {
  const summary = (data.value.summaries || []).find(item => item.examId === items[0].examId) || {};
  const { downloadScoreReport } = await import(/* @vite-ignore */ '/js/client/pdf-export.js');
  await downloadScoreReport({
    organization: sessionStore.state.publicData.organization,
    candidate: data.value.candidate || { name: sessionStore.state.profile?.name || sessionStore.state.user?.displayName, candidateNumber: sessionStore.state.user?.candidateNumber },
    exam: { id: items[0].examId, name: items[0].examName, code: items[0].examCode }, results: items,
    summary: { ...summary, publishedAt: [...items].sort((a,b) => new Date(b.publishedAt) - new Date(a.publishedAt))[0]?.publishedAt },
    verificationCode: summary.verificationCode, verificationQr: summary.verificationQr,
    verificationUrl: `${location.origin}/verify/${summary.verificationCode}`
  });
}
async function downloadAdmission(item) {
  const { downloadAdmissionNotice } = await import(/* @vite-ignore */ '/js/client/pdf-export.js');
  await downloadAdmissionNotice({
    organization: sessionStore.state.publicData.organization,
    candidate: { name: sessionStore.state.profile?.name || sessionStore.state.user?.displayName }, exam: item.exam,
    placement: item.placement, school: item.placementSchool || { name: item.placement?.schoolName || '招生学校' }, template: item.noticeTemplate || {},
    verificationCode: item.noticeVerificationCode, verificationQr: item.noticeVerificationQr, noticeNumber: item.noticeNumber,
    verificationUrl: `${location.origin}/verify/${item.noticeVerificationCode}`
  });
}
function openNotice(id) { router.push(`/announcements/${id}`); }

watch(() => props.page, load);
onMounted(load);
</script>

<template>
  <main v-if="page === 'onboarding'" class="candidate-onboarding">
    <aside><RouterLink class="app-brand app-brand--light" to="/"><span>衡</span><div><strong>衡准考试服务</strong><small>FIRST SIGN-IN</small></div></RouterLink><p>固定报名号</p><strong>{{ sessionStore.state.user?.candidateNumber }}</strong><span>完成首次登录设置后，这个号码将用于所有考试事项。</span></aside>
    <section><PageState :loading="loading" :error="error" @retry="load">
      <form v-if="sessionStore.state.user?.mustChangePassword" class="business-form onboarding-form" @submit.prevent="changePassword(true)"><p>STEP 1</p><h1>先保护你的账户</h1><span>初始密码只用于第一次登录，请设置仅本人知道的新密码。</span><label><span>当前初始密码</span><input v-model="passwordForm.currentPassword" type="password" required></label><label><span>设置新密码</span><input v-model="passwordForm.newPassword" type="password" minlength="8" required></label><label><span>再次输入新密码</span><input v-model="passwordForm.confirmPassword" type="password" minlength="8" required></label><button class="app-button app-button--primary app-button--large" :disabled="saving">保存新密码并继续</button></form>
      <form v-else class="business-form profile-editor" @submit.prevent="saveProfile(true)"><p>STEP 2</p><h1>建立完整考生档案</h1><ProfileFields :form="profileForm" :schools="data.schools || []" :classes="classesForSchool" /><button class="app-button app-button--primary app-button--large" :disabled="saving">提交个人信息</button></form>
    </PageState></section>
  </main>

  <PortalShell v-else role="candidate" :page="page" :title="meta[0]" :description="meta[1]">
    <PageState :loading="loading" :error="error" @retry="load">
      <template v-if="page === 'dashboard'">
        <section class="candidate-welcome-vue"><div><span>{{ new Date().getHours() < 12 ? '上午好' : '下午好' }}</span><h2>{{ data.profile?.name || sessionStore.state.user?.displayName }}，欢迎回来。</h2><p>{{ data.profile?.status === 'approved' ? '资料已通过审核，可以继续办理考试事项。' : '个人资料正在审核中，通过后即可报名考试。' }}</p></div><strong>准<br>考</strong></section>
        <section class="record-metrics"><article><span>个人资料</span><strong><StatusBadge :value="data.profile?.status || 'pending'" /></strong></article><article><span>已报名考试</span><strong>{{ data.registrations?.length || 0 }}</strong></article><article><span>可下载准考证</span><strong>{{ data.registrations?.filter(item => item.admitCard).length || 0 }}</strong></article><article><span>已发布成绩</span><strong>{{ data.results?.length || 0 }}</strong></article></section>
        <div class="candidate-dashboard-grid"><section class="record-panel"><header><div><h2>最近报名</h2><p>考试办理状态实时更新</p></div></header><button v-for="item in data.registrations?.slice(0, 4)" :key="item.id" class="dashboard-row" type="button" @click="router.push('/candidate/registrations')"><span><strong>{{ item.exam?.name }}</strong><small>{{ item.subjects?.length || 0 }} 个科目</small></span><StatusBadge :value="item.status" /></button></section><section class="record-panel"><header><div><h2>最近通知</h2><p>考试中心正式发布</p></div></header><button v-for="notice in data.notices?.slice(0, 5)" :key="notice.id" class="dashboard-row" type="button" @click="openNotice(notice.id)"><span><strong>{{ notice.title }}</strong><small>{{ formatDate(notice.publishAt) }}</small></span><i>→</i></button></section></div>
      </template>

      <form v-else-if="page === 'profile'" class="business-form profile-editor" @submit.prevent="saveProfile(false)"><ProfileFields :form="profileForm" :schools="data.schools || []" :classes="classesForSchool" /><div v-if="data.profile?.reviewNote" class="form-callout"><strong>审核意见</strong><p>{{ data.profile.reviewNote }}</p></div><button class="app-button app-button--primary" :disabled="saving">保存并提交审批</button></form>

      <div v-else-if="page === 'exams'" class="business-card-list"><article v-for="exam in data.exams" :key="exam.id" class="exam-apply-card"><header><span>{{ exam.code }}</span><StatusBadge :value="exam.registrationState" /></header><h2>{{ exam.name }}</h2><p>{{ exam.description }}</p><dl><div><dt>报名期限</dt><dd>{{ dateRange(exam.registrationStart, exam.registrationEnd) }}</dd></div><div><dt>考试时间</dt><dd>{{ dateRange(exam.examStart, exam.examEnd) }}</dd></div><div><dt>计分规则</dt><dd>总分 {{ exam.totalScore }} · {{ passPolicyText(exam) }}</dd></div></dl><div class="subject-choice-grid"><label v-for="subject in exam.subjects" :key="subject.id"><input v-model="selectedSubjects[exam.id]" type="checkbox" :value="subject.id" :disabled="Boolean(exam.registration)"><span><strong>{{ subject.name }}</strong><small>{{ subject.date }} {{ subject.start }} · 满分 {{ subject.fullScore }}</small><em>{{ money(subject.fee) }}</em></span></label></div><footer v-if="exam.registration"><span>已提交 {{ exam.registration.subjectIds?.length || 0 }} 个科目</span><StatusBadge :value="exam.registration.status" /></footer><button v-else class="app-button app-button--primary" type="button" :disabled="saving || exam.registrationState !== 'open' || data.profileStatus !== 'approved'" @click="registerExam(exam)">{{ data.profileStatus !== 'approved' ? '资料审核通过后可报名' : '提交考试报名' }}</button></article></div>

      <div v-else-if="page === 'registrations'" class="business-card-list"><article v-for="item in registrations" :key="item.id" class="registration-vue-card"><header><div><span>{{ item.exam?.code }}</span><h2>{{ item.exam?.name }}</h2></div><StatusBadge :value="item.exam?.archivedAt ? 'archived' : item.status" /></header><dl><div><dt>账户报名号</dt><dd>{{ item.registrationNumber || sessionStore.state.user?.candidateNumber }}</dd></div><div><dt>当前审批</dt><dd>{{ item.workflow?.currentStepDetail?.name || (item.workflow?.status ? statusLabel(item.workflow.status) : '待提交') }}</dd></div><div><dt>应缴金额</dt><dd>{{ money(item.amountDue) }}</dd></div><div><dt>缴费状态</dt><dd><StatusBadge :value="item.paymentStatus" /></dd></div></dl><div class="chip-list"><span v-for="subject in item.subjects" :key="subject.id">{{ subject.name }}<small>{{ subject.date }} {{ subject.start }}</small></span></div><p v-if="item.reviewNote">审核意见：{{ item.reviewNote }}</p></article><div v-if="!registrations.length" class="page-state page-state--empty"><strong>还没有考试报名</strong><p>资料审核通过后，可在“考试报名”中选择考试与科目。</p></div></div>

      <div v-else-if="page === 'admit'" class="business-card-list"><article v-for="item in registrations.filter(row => row.admitCard)" :key="item.id" class="admit-card-vue"><header><span>{{ item.exam.code }}</span><StatusBadge :value="item.exam.archivedAt ? 'archived' : 'open'" /></header><h2>{{ item.exam.name }}</h2><div><small>准考证号</small><strong>{{ item.admitCard.number }}</strong></div><dl><div><dt>固定考点</dt><dd>{{ item.admitCard.testCenter }}</dd></div><div><dt>下载时间</dt><dd>{{ dateRange(item.exam.admitDownloadStart, item.exam.admitDownloadEnd) }}</dd></div></dl><button class="app-button app-button--primary" type="button" :disabled="Boolean(item.exam.archivedAt)" @click="downloadAdmit(item.id)">下载准考证</button></article><div v-if="!registrations.some(row => row.admitCard)" class="page-state page-state--empty"><strong>准考证尚未生成</strong><p>管理员统一编排后会显示在这里。</p></div></div>

      <div v-else-if="page === 'results'" class="business-card-list"><section v-for="items in groupedResults" :key="items[0].examId" class="record-panel result-group"><header><div><span>{{ items[0].examCode }}</span><h2>{{ items[0].examName }}</h2></div><button class="app-button app-button--primary" type="button" @click="downloadScore(items)">下载 PDF 成绩单</button></header><div class="result-card-grid"><article v-for="result in items" :key="result.id"><span>{{ result.subjectName }}</span><strong>{{ result.score }}<small>/ {{ result.fullScore }}</small></strong><em>{{ result.grade }} · 第 {{ result.rank }} / {{ result.cohortSize }} 名</em><StatusBadge v-if="result.appeal" :value="result.appeal.status" /><form v-else @submit.prevent="submitAppeal(result)"><textarea v-model="appealReasons[result.id]" rows="2" placeholder="填写成绩复议理由"></textarea><button type="submit">申请复议</button></form></article></div></section><div v-if="!groupedResults.length" class="page-state page-state--empty"><strong>暂时没有已发布成绩</strong><p>成绩发布后会显示在这里。</p></div></div>

      <div v-else-if="page === 'admissions'" class="business-card-list"><section v-for="item in data.admissions" :key="item.examId" class="record-panel admission-candidate-vue"><header><div><span>{{ item.exam.code }} · 第 {{ item.payload?.round || 1 }} 轮</span><h2>{{ item.exam.name }}</h2></div><StatusBadge :value="item.status" /></header><div class="record-metrics"><article><span>本场总成绩</span><strong>{{ item.totalScore ?? '未完整发布' }}</strong></article><article><span>特征分</span><strong>{{ item.featureScore || 0 }}</strong></article><article><span>已提交志愿</span><strong>{{ item.submissionCount || 0 }} / {{ item.maxSubmissions || item.payload?.maxSubmissions || 0 }}</strong></article></div><div v-if="item.placement" class="form-callout"><strong>当前录取结果：{{ item.placementSchool?.name || item.placement.schoolName || '招生学校' }}</strong><p>{{ item.placement.payload?.categoryName }} · {{ statusLabel(item.placement.status) }}</p><button v-if="item.placement.status === 'final'" class="app-button app-button--primary" type="button" @click="downloadAdmission(item)">下载录取通知书 PDF</button></div><form v-if="['filling','supplementary'].includes(item.status) && !item.preferenceLocked && item.supplementEligible !== false" class="preference-editor" @submit.prevent="savePreferences(item)"><div v-for="(choice, index) in preferenceDrafts[item.examId]" :key="index" class="preference-row"><b>{{ choice.preferenceType === 'indicator' ? '指标' : index }}</b><select v-model="choice.schoolId" @change="choice.categoryCode = ''"><option value="">选择招生学校</option><option v-for="plan in availablePlans(item, choice.preferenceType)" :key="plan.schoolId" :value="plan.schoolId">{{ plan.schoolCode }} · {{ plan.schoolName }}</option></select><select v-model="choice.categoryCode" :disabled="!choice.schoolId"><option value="">选择招生类别</option><option v-for="category in categoriesFor(item, choice)" :key="category.code" :value="category.code">{{ category.name }}</option></select></div><button class="app-button app-button--primary">保存本人志愿</button></form><p v-else>{{ item.supplementIneligibilityReason || item.payload?.progress || '当前阶段不能修改志愿。' }}</p></section><div v-if="!data.admissions?.length" class="page-state page-state--empty"><strong>暂无志愿填报安排</strong><p>成绩发布且考试启用志愿后会显示在这里。</p></div></div>

      <section v-else-if="page === 'notices'" class="record-panel notice-list-vue"><button v-for="notice in data.notices" :key="notice.id" type="button" @click="openNotice(notice.id)"><time>{{ formatDate(notice.publishAt) }}</time><span><em>{{ notice.category }}</em><strong>{{ notice.title }}</strong><small>{{ notice.summary }}</small></span><i>→</i></button></section>

      <AccountSecurity v-else-if="page === 'security'" :status="data" @updated="load" />
    </PageState>
  </PortalShell>
</template>
