import { ref, reactive, computed } from 'vue'
import { message } from 'ant-design-vue'
import { examAPI } from '../../../api/exam.js'
import questionAPI from '../../../api/question.js'

export function useExam() {
  const examTab = ref('pending')
  const pendingPapers = ref([])
  const currentTakingPaper = ref(null)
  const completedResults = ref([])
  const loading = ref(false)
  const examDetailData = ref(null)
  const examDetailLoading = ref(false)
  const examDetailError = ref('')
  const isGeneratingSelftest = ref(false)
  const isSelfTest = ref(false)

  const _paperQuestionsCache = new Map()

  const selftestConfig = reactive({
    singleChoiceCount: 5,
    multipleChoiceCount: 3,
    trueFalseCount: 2,
    fillBlankCount: 0,
    subjectiveCount: 0,
    difficulty: 3
  })

  const examStats = computed(() => [
    { value: pendingPapers.length, label: '待考试' },
    { value: completedResults.length, label: '已完成' }
  ])

  const _getStatus = (record) => {
    return (record?.status || record?.examStatus || record?.paperStatus || record?.state || record?.record_status || '').toLowerCase()
  }

  const _EXCLUDED_STATUSES = ['pending', 'not_started', 'waiting', 'available', 'in_progress', 'expired', 'cancelled']

const _isFinished = (record) => {
    const s = _getStatus(record)
    return ['graded', 'completed', 'submitted'].includes(s)
  }

  const _getBlacklistKey = () => 'exam_finished_record_blacklist'
  const _loadBlacklist = () => {
    try { return new Set(JSON.parse(sessionStorage.getItem(_getBlacklistKey()) || '[]')) } catch { return new Set() }
  }
  const _saveBlacklist = (set) => {
    try { sessionStorage.setItem(_getBlacklistKey(), JSON.stringify([...set])) } catch {}
  }
  const _addToBlacklist = (recordId, realStatus, paperTitle, score = null) => {
    const bl = _loadBlacklist()
    const existing = [...bl].filter(e => {
      try { return JSON.parse(e).id !== recordId } catch { return true }
    })
    existing.push(JSON.stringify({ id: recordId, status: realStatus, title: paperTitle || '', score, ts: Date.now() }))
    _saveBlacklist(new Set(existing))
  }
  const _isBlacklisted = (recordId) => {
    const bl = _loadBlacklist()
    for (const entry of bl) {
      try { if (JSON.parse(entry).id === recordId) return true } catch {}
    }
    return false
  }
  const _cleanOldBlacklist = () => {
    // sessionStorage 在标签页关闭后自动清除，无需额外清理
  }

  const _mapToCompletedResult = (r) => ({
    ...r,
    id: r.recordId || r.id,
    recordId: r.recordId || r.id,
    paperId: r.paperId || r.paper_id,
    answerType: r.answerType || r.answer_type || 'formal_exam',
    paperTitle: r.paperTitle || r.paperName || r.title || r.name || '试卷',
    score: r.totalScore != null ? Number(r.totalScore) : (r.score != null ? Number(r.score) : 0),
    totalMaxScore: r.totalMaxScore || r.total_max_score || 100,
    accuracy: r.scoreRate != null ? Math.round(Number(r.scoreRate) * 100) : 0,
    timeUsed: r.timeSpent != null ? Math.floor(Number(r.timeSpent) / 60) : (r.duration || 0),
    completedAt: r.submitTime || r.completedAt || r.submittedAt || r.updatedAt || ''
  })

  const loadPendingPapers = async () => {
    loading.value = true
    let loaded = false
    let leakedFinished = []
    _cleanOldBlacklist()

    const _tryMainApi = async () => {
      try {
        console.log('[待考试] 尝试主API /exam/paper/pending ...')
        const response = await examAPI.getPendingList()
        console.log('[待考试] 主API返回:', JSON.stringify(response).substring(0, 1500))

        let data = null
        if (Array.isArray(response)) { data = response }
        else if (response && typeof response === 'object') {
          for (const key of ['list', 'data', 'records', 'rows', 'items', 'papers', 'content', 'pendingList', 'pending_list', 'exams']) {
            if (Array.isArray(response[key])) { data = response[key]; break }
          }
          if (!data && Array.isArray(response.data?.list)) data = response.data.list
          if (!data) {
            for (const key of Object.keys(response)) {
              if (Array.isArray(response[key]) && response[key].length > 0) { data = response[key]; break }
            }
          }
        }

        if (!Array.isArray(data)) data = []
        console.log(`[待考试] 主API原始 ${data.length} 条`)
        if (data.length > 0) {
          console.log('[待考试] 🔍 首条记录完整字段:', JSON.stringify(data[0], null, 2))
          console.log('[待考试] 🔍 状态分布:', [...new Set(data.map(p => _getStatus(p)))])
          console.log('[待考试] 🔍 所有字段名:', Object.keys(data[0]))
        }

        const finishedRecords = data.filter(_isFinished)
        if (finishedRecords.length > 0) {
          console.warn(`[待考试] ⚠️ 主API泄漏了 ${finishedRecords.length} 条已结束记录! 状态:`, finishedRecords.map(r => _getStatus(r)))
          leakedFinished.push(...finishedRecords)
        } else if (data.length > 0) {
          const fullText = JSON.stringify(data[0]).toLowerCase()
          const hasGradedHint = /\b(graded|completed|submitted|批改|完成|已交|结束)\b/.test(fullText)
          if (hasGradedHint) {
            console.warn('[待考试] ⚠️ _isFinished未命中但数据中包含结束状态关键词! 全文搜索匹配')
            const keywordFinished = data.filter(item => /\b(graded|completed|submitted)\b/.test(JSON.stringify(item).toLowerCase()))
            if (keywordFinished.length > 0) {
              console.warn(`[待考试] ⚠️ 关键词匹配到 ${keywordFinished.length} 条，强制过滤`)
              leakedFinished.push(...keywordFinished)
              data = data.filter(item => !keywordFinished.includes(item))
            }
          }
        }
        data = data.filter(r => !_isFinished(r))

        // 黑名单过滤：仅当 API 状态也确认已结束时才过滤，避免跨浏览器/跨会话不一致
        const blacklistedInMain = data.filter(r => {
          if (!_isBlacklisted(r.id || r.paperId || r.recordId || r.record_id)) return false
          // 双重确认：API 状态也必须指示已结束
          if (_isFinished(r)) return true
          const fullText = JSON.stringify(r).toLowerCase()
          if (/\b(graded|completed|submitted)\b/.test(fullText)) return true
          console.warn(`[待考试] ⚠️ 记录 ${r.id || r.paperId} 在黑名单但API状态为 "${_getStatus(r)}"，跳过黑名单过滤`)
          return false
        })
        if (blacklistedInMain.length > 0) {
          console.warn(`[待考试] 🚫 黑名单过滤: 排除 ${blacklistedInMain.length} 条已结束记录`)
          leakedFinished.push(...blacklistedInMain)
        }
        data = data.filter(r => {
          if (!_isBlacklisted(r.id || r.paperId || r.recordId || r.record_id)) return true
          if (_isFinished(r)) return false
          const fullText = JSON.stringify(r).toLowerCase()
          if (/\b(graded|completed|submitted)\b/.test(fullText)) return false
          return true // 黑名单但API状态不匹配 → 不过滤
        })

        if (data.length > 0) {
          console.log('[待考试] 主API命中, 首条keys:', Object.keys(data[0]))
          // 诊断：检查题数字段
          const first = data[0]
          console.log('[待考试] 🔍 题数字段诊断:', {
            questionCount: first.questionCount,
            question_count: first.question_count,
            questionNum: first.questionNum,
            questions: first.questions?.length,
            questionIds: first.questionIds?.length,
            question_ids: first.question_ids?.length,
            fieldList: Object.keys(first).filter(k => k.toLowerCase().includes('question') || k.toLowerCase().includes('count') || k.toLowerCase().includes('num'))
          })
          pendingPapers.value = data.map(p => ({
            id: p.id || p.paperId || p.paper_id || p.recordId || p.record_id,
            paperId: p.paperId || p.paper_id || p.id,
            title: p.title || p.paperTitle || p.paper_title || p.name || p.paperName || '未命名试卷',
            questionCount: p.questionCount || p.question_count || p.questionNum || p.questions?.length || p.questionIds?.length || p.question_ids?.length || 0,
            totalScore: p.totalScore || p.total_score || p.score || 0,
            duration: p.duration || p.timeLimit || p.time_limit || 60,
            deadline: p.deadline || p.deadline_time || p.endTime || p.end_time || '',
            publishTime: p.publishTime || p.publish_time || p.createdAt || p.created_at || '',
            status: _getStatus(p) || 'pending'
          }))
          loaded = true
          console.log(`[待考试] 主API加载成功, 共 ${pendingPapers.value.length} 条`)
        } else {
          console.log('[待考试] 主API返回空数组(过滤后)')
        }
      } catch (e) {
        console.error('[待考试] ❌ 主API异常详情:', e.message || e)
        if (e.response) {
          console.error('[待考试] ❌ 主API HTTP状态:', e.response.status, '响应数据:', JSON.stringify(e.response.data)?.substring(0, 500))
        }
        if (e.response?.data) {
          const errData = e.response.data
          console.warn('[待考试] 🔍 主API错误响应完整内容:', JSON.stringify(errData, null, 2))
          const errArr = Array.isArray(errData) ? errData : (errData.list || errData.data || errData.records || null)
          if (Array.isArray(errArr)) {
            console.warn(`[待考试] 🔍 主API错误响应中发现 ${errArr.length} 条数组数据，尝试直接使用`)
            const finishedInErr = errArr.filter(_isFinished)
            if (finishedInErr.length > 0) {
              console.warn(`[待考试] ⚠️ 错误响应中包含 ${finishedInErr.length} 条已结束记录!`)
              leakedFinished.push(...finishedInErr)
            }
            const validPending = errArr.filter(r => !_isFinished(r))
            if (validPending.length > 0 && !loaded) {
              pendingPapers.value = validPending.map(p => ({
                id: p.id || p.paperId || p.paper_id || p.recordId || p.record_id,
                paperId: p.paperId || p.paper_id || p.id,
                title: p.title || p.paperTitle || p.paper_title || p.name || p.paperName || '未命名试卷',
                questionCount: p.questionCount || p.question_count || p.questionNum || p.questions?.length || p.questionIds?.length || p.question_ids?.length || 0,
                totalScore: p.totalScore || p.total_score || p.score || 0,
                duration: p.duration || p.timeLimit || p.time_limit || 60,
                deadline: p.deadline || p.deadline_time || p.endTime || p.end_time || '',
                publishTime: p.publishTime || p.publish_time || p.createdAt || p.created_at || '',
                status: _getStatus(p) || 'pending'
              }))
              loaded = true
              console.log(`[待考试] 从错误响应恢复 ${pendingPapers.value.length} 条记录`)
            }
          }
        }
      }
    }

    const _tryFallbackApi = async () => {
      if (loaded) return
      console.log('[待考试] 尝试备选API /exam/records?type=formal_exam ...')
      try {
        const recordsRes = await examAPI.getExamRecords('formal_exam')
        console.log('[待考试] 备选API返回:', JSON.stringify(recordsRes).substring(0, 1000))
        let records = Array.isArray(recordsRes) ? recordsRes : (recordsRes?.list || recordsRes?.data || recordsRes?.records || [])
        if (!Array.isArray(records)) records = []
        console.log(`[待考试] 备选API共 ${records.length} 条记录, 状态分布:`, [...new Set(records.map(r => _getStatus(r)))])

        const pendingStatuses = ['pending', 'published', 'assigned', 'waiting', 'not_started', 'available', 'in_progress']
        let pendingRecords = records.filter(r => pendingStatuses.includes(_getStatus(r)))

        const finishedInPending = pendingRecords.filter(_isFinished)
        if (finishedInPending.length > 0) {
          console.warn(`[待考试] ⚠️ 白名单内发现 ${finishedInPending.length} 条已结束记录! 状态:`, finishedInPending.map(r => _getStatus(r)))
          leakedFinished.push(...finishedInPending)
          pendingRecords = pendingRecords.filter(r => !_isFinished(r))
        }

        const blacklistedRecords = pendingRecords.filter(r => {
          if (!_isBlacklisted(r.id || r.recordId)) return false
          if (_isFinished(r)) return true
          const fullText = JSON.stringify(r).toLowerCase()
          if (/\b(graded|completed|submitted)\b/.test(fullText)) return true
          return false
        })
        if (blacklistedRecords.length > 0) {
          console.warn(`[待考试] 🚫 黑名单过滤: 排除 ${blacklistedRecords.length} 条已结束记录(后端状态与列表不一致)`)
          pendingRecords = pendingRecords.filter(r => {
            if (!_isBlacklisted(r.id || r.recordId)) return true
            if (_isFinished(r)) return false
            const fullText = JSON.stringify(r).toLowerCase()
            if (/\b(graded|completed|submitted)\b/.test(fullText)) return false
            return true
          })
        }

        if (pendingRecords.length > 0) {
          pendingPapers.value = pendingRecords.map(r => ({
            id: r.paperId || r.paper_id || r.id || r.recordId || r.record_id,
            paperId: r.paperId || r.paper_id || '',
            recordId: r.id || r.recordId || r.record_id || '',
            title: r.paperTitle || r.paper_title || r.title || r.name || '试卷',
            questionCount: r.questionCount || r.question_count || 0,
            totalScore: r.totalScore || r.total_score || 100,
            duration: r.duration || 60,
            deadline: r.deadline || '',
            publishTime: r.publishTime || r.createdAt || '',
            status: _getStatus(r) || 'pending',
            _source: 'records'
          }))
          loaded = true
          console.log(`[待考试] 备选API找到 ${pendingPapers.value.length} 条待考试/进行中记录`)
        } else {
          console.log('[待考试] 备选API无匹配的待考试状态记录')
          pendingPapers.value = []
        }
      } catch (fallbackErr) {
        console.warn('[待考试] 备选API也失败:', fallbackErr.message?.substring(0, 120))
        pendingPapers.value = []
      }
    }

    await _tryMainApi()
    await _tryFallbackApi()

    if (leakedFinished.length > 0) {
      console.log(`[数据分流] 将 ${leakedFinished.length} 条泄漏的已结束记录自动转入成绩单`)
      const existingIds = new Set(completedResults.value.map(r => r.recordId || r.id))
      const newResults = leakedFinished
        .filter(r => !existingIds.has(r.recordId || r.id))
        .map(_mapToCompletedResult)
      if (newResults.length > 0) {
        completedResults.value = [...newResults, ...completedResults.value]
      }
    }

    loading.value = false
  }

  const startExam = async (idOrPaper) => {
    const _resolveIds = (input) => {
      if (typeof input === 'object' && input !== null) {
        return { paperId: input.paperId || input.id, recordId: input.recordId || '', title: input.title }
      }
      const found = pendingPapers.value.find(p => p.id === input || p.paperId === input || p.recordId === input)
      return { paperId: found?.paperId || found?.id || String(input), recordId: found?.recordId || '', title: found?.title || '' }
    }

    const _detectStatusError = (errMsg) => {
      if (!errMsg) return null
      const lower = errMsg.toLowerCase()
      const statusMap = {
        'graded': '该试卷已批改完成，无法重新开始考试',
        'completed': '该考试已完成，无法重新开始',
        'submitted': '该试卷已提交，无法重新开始考试',
        'expired': '该考试已过期，无法开始',
        'cancelled': '该考试已取消，无法开始',
        'not_allowed': '当前状态不允许开始此考试',
        '不允许': '当前状态不允许开始此考试',
        '系统异常': '后端服务异常，请稍后重试',
      }
      for (const [key, msg] of Object.entries(statusMap)) {
        if (lower.includes(key)) {
          const statusMatch = errMsg.match(/当前状态[：:]\s*(\w+)/i)
          const realStatus = (statusMatch?.[1] || key).toLowerCase()
          return { msg, realStatus }
        }
      }
      return null
    }

    const { paperId, recordId } = _resolveIds(idOrPaper)
    console.log('[开始考试] 解析ID → paperId:', paperId, 'recordId:', recordId)

    let response = null
    let usedApi = ''

    if (paperId) {
      try {
        console.log('[开始考试] 尝试按试卷ID启动 /formal-exam/paper/start ...')
        response = await examAPI.startFormalExamByPaperId(paperId)
        usedApi = 'paper'
        console.log('[开始考试] 试卷API成功')
      } catch (paperErr) {
        console.warn('[开始考试] 试卷API失败:', paperErr.message?.substring(0, 100))
        const statusResult = _detectStatusError(paperErr.message)
        if (statusResult) {
          message.warning(statusResult.msg)
          _addToBlacklist(recordId || paperId, statusResult.realStatus, '')
          loadPendingPapers()
          return
        }
        if (recordId) {
          try {
            console.log('[开始考试] 降级按记录ID启动 /exam/record/start ...')
            response = await examAPI.startExamRecord(recordId)
            usedApi = 'record'
            console.log('[开始考试] 记录API成功')
          } catch (recordErr) {
            console.error('[开始考试] 记录API也失败:', recordErr.message?.substring(0, 100))
            const recordStatusResult = _detectStatusError(recordErr.message)
            if (recordStatusResult) {
              message.warning(recordStatusResult.msg)
              _addToBlacklist(recordId || paperId, recordStatusResult.realStatus, '')
              loadPendingPapers()
              return
            }
            message.error('无法启动考试，请稍后重试')
          }
        } else {
          message.error('无法启动考试：' + (paperErr.message?.substring(0, 50) || '未知错误'))
        }
        return
      }
    } else if (recordId) {
      try {
        console.log('[开始考试] 按记录ID启动 /exam/record/start ...')
        response = await examAPI.startExamRecord(recordId)
        usedApi = 'record'
      } catch (e) {
        const statusResult = _detectStatusError(e.message)
        if (statusResult) {
          message.warning(statusResult.msg)
          _addToBlacklist(recordId || paperId, statusResult.realStatus, '')
          loadPendingPapers()
          return
        }
        message.error('无法启动考试：' + (e.message?.substring(0, 50) || '未知错误'))
        return
      }
    } else {
      message.error('缺少有效的试卷或记录ID')
      return
    }

    console.log('[开始考试] API返回:', JSON.stringify(response).substring(0, 1000), '| 使用接口:', usedApi)

    let paper = null
    if (response?.data && typeof response.data === 'object') {
      paper = response.data
    } else if (response && typeof response === 'object' && !Array.isArray(response)) {
      paper = response
    } else {
      paper = { id: paperId || recordId, title: '试卷', questions: [] }
    }

    let rawQuestions = paper.questions || []
    if (!Array.isArray(rawQuestions) || rawQuestions.length === 0) {
      for (const k of ['questionList', 'question_list', 'items', 'data', 'content']) {
        if (Array.isArray(paper[k]) && paper[k].length > 0) { rawQuestions = paper[k]; break }
      }
    }
    if (!Array.isArray(rawQuestions)) rawQuestions = []
    console.log(`[开始考试] 解析到 ${rawQuestions.length} 道题目`)

    currentTakingPaper.value = {
      id: paper.id || paper.recordId || paper.record_id || paperId || recordId,
      recordId: paper.recordId || paper.record_id || (usedApi === 'record' ? recordId : '') || paper.id,
      paperId: paper.paperId || paper.paper_id || (usedApi === 'paper' ? paperId : '') || recordId,
      title: paper.title || paper.paperTitle || paper.paper_title || paper.name || '试卷',
      duration: paper.duration || paper.timeLimit || 60,
      remainingTime: (paper.duration || paper.timeLimit || 60) * 60,
      questions: rawQuestions.map((q, idx) => {
        let qContent = {}
        if (q.content && typeof q.content === 'object') qContent = q.content
        else if (typeof q.content === 'string' && q.content.trim().startsWith('{')) {
          try { qContent = JSON.parse(q.content) } catch(e) {}
        } else if (q.data && typeof q.data === 'object') qContent = q.data

        if (qContent.data && typeof qContent.data === 'object' && !Array.isArray(qContent.data)) {
          const inner = qContent.data
          if (!qContent.stem && inner.stem) qContent.stem = inner.stem
          if ((!qContent.options || !Array.isArray(qContent.options) || qContent.options.length === 0) && Array.isArray(inner.options)) qContent.options = inner.options
          if (!qContent.answer && inner.answer) qContent.answer = inner.answer
          if (!qContent.explanation && inner.explanation) qContent.explanation = inner.explanation
        }

        const _normalizeOptions = (opts) => {
          if (!opts) return []
          if (Array.isArray(opts)) return opts.map(o => {
            if (typeof o === 'string') return { key: String.fromCharCode(65 + opts.indexOf(o)), text: o, content: o }
            return {
              key: o.key || o.label || o.optionKey || '',
              text: o.text || o.content || o.value || o.optionText || '',
              content: o.content || o.text || o.value || ''
            }
          })
          if (typeof opts === 'object') return Object.keys(opts).map(k => ({ key: k, text: opts[k], content: opts[k] }))
          return []
        }

        return {
          id: q.id || q.questionId || q.question_id || idx + 1,
          questionId: q.questionId || q.question_id || q.id,
          type: (q.type || q.questionType || q.question_type || '').toLowerCase(),
          stem: qContent.stem || q.stem || q.questionStem || q.question_content || (typeof q.content === 'string' ? q.content : '') || '',
          options: _normalizeOptions(qContent.options || q.options),
          answer: qContent.answer || q.answer || q.correctAnswer || '',
          score: q.score || q.maxScore || q.max_score || 5,
          maxScore: q.maxScore || q.max_score || q.score || 5,
          studentAnswer: q.studentAnswer ?? q.student_answer ?? null
        }
      })
    }
    if (paperId && currentTakingPaper.value?.questions?.length > 0) {
      _paperQuestionsCache.set(paperId, currentTakingPaper.value.questions.map(q => ({
        questionId: q.questionId,
        questionType: q.type || q.questionType || '',
        stem: q.stem || '',
        options: q.options || [],
        answer: q.answer || q.correctAnswer || '',
        score: q.score || 5
      })))
      console.log('[开始考试] 已缓存题目数据, paperId:', paperId, '题数:', currentTakingPaper.value.questions.length)
    }
    isSelfTest.value = false
    examTab.value = 'taking'
    message.success('开始答题')
  }

  const startSelftest = async () => {
    const totalCount = selftestConfig.singleChoiceCount + selftestConfig.multipleChoiceCount +
      selftestConfig.trueFalseCount + selftestConfig.fillBlankCount + selftestConfig.subjectiveCount
    if (totalCount <= 0) {
      message.warning('请至少设置一种题型的数量')
      return
    }

    isGeneratingSelftest.value = true
    try {
      const params = {
        single_choice_count: selftestConfig.singleChoiceCount,
        multiple_choice_count: selftestConfig.multipleChoiceCount,
        true_false_count: selftestConfig.trueFalseCount,
        fill_blank_count: selftestConfig.fillBlankCount,
        subjective_count: selftestConfig.subjectiveCount,
        include_personal: false,
        difficulty: selftestConfig.difficulty
      }
      console.log('[自测组卷] 生成参数:', params)

      const result = await examAPI.generatePaper(params)

      const rawQuestions = result.questions || []
      if (rawQuestions.length === 0) {
        message.warning('题库中暂无符合条件的题目，请调整参数后重试')
        return
      }

      currentTakingPaper.value = {
        id: Date.now(),
        recordId: null,
        title: '自测卷 - ' + new Date().toLocaleString(),
        questions: rawQuestions.map((q, idx) => ({
          id: idx + 1,
          questionId: q.question_id || q.questionId,
          type: q.question_type || q.questionType,
          stem: q.content?.stem || q.stem || '',
          options: q.content?.data?.options || q.content?.options || [],
          answer: q.content?.answer || q.answer || '',
          score: q.score || 5,
          maxScore: q.score || 5,
          studentAnswer: null
        }))
      }
      isSelfTest.value = true
      examTab.value = 'taking'
      message.success(`自测卷生成成功，共 ${rawQuestions.length} 题，开始答题！`)
    } catch (error) {
      console.error('[自测组卷] 生成失败:', error)
      message.error('生成失败: ' + (error.message || '请稍后重试'))
    } finally {
      isGeneratingSelftest.value = false
    }
  }

  // In-memory buffer for just-submitted exam result (used by loadExamResults)
  let _pendingSubmitResult = null

  const submitExam = async () => {
    if (!currentTakingPaper.value) return

    if (isSelfTest.value) {
      const questions = currentTakingPaper.value.questions || []
      try {
        const formattedAnswers = questions.map(q => {
          const optionsData = (q.options || []).map(opt => ({
            key: opt.key || opt.label || '',
            content: opt.content || opt.text || ''
          }))
          return {
            questionId: q.questionId || q.id,
            questionType: q.type,
            questionContent: {
              stem: q.stem || '',
              data: { options: optionsData },
              answer: q.answer != null ? q.answer : ''
            },
            studentAnswer: q.studentAnswer != null ? String(q.studentAnswer) : '',
            maxScore: q.maxScore || q.score || 5
          }
        })

        const result = await examAPI.gradeAnswers({
          answers: formattedAnswers,
          type: 'practice'
        })

        message.success('提交成功！')

        const resultQuestions = result.results || result.answers || result.questions || []
        examDetailData.value = {
          recordId: 'self_' + Date.now(),
          paperId: null,
          paperTitle: currentTakingPaper.value.title || '自测卷',
          totalScore: result.totalScore ?? result.total_score ?? 0,
          totalMaxScore: result.totalMaxScore ?? result.total_max_score ?? null,
          scoreRate: result.scoreRate ?? result.score_rate ?? null,
          submitTime: new Date().toLocaleString(),
          questions: questions.map((q, idx) => {
            const r = resultQuestions[idx] || {}
            return {
              questionId: q.questionId || q.id,
              questionType: q.type,
              content: { stem: q.stem, data: { options: q.options }, answer: q.answer },
              studentAnswer: q.studentAnswer ?? '',
              correctAnswer: q.answer || '',
              score: r.score ?? r.studentScore ?? 0,
              maxScore: r.maxScore ?? r.totalScore ?? q.maxScore ?? q.score ?? null,
              isCorrect: r.isCorrect ?? r.is_correct ?? r.correct ?? null,
              feedback: r.feedback || ''
            }
          })
        }
        currentTakingPaper.value = null
        examTab.value = 'detail'
      } catch (error) {
        console.error('提交自测卷失败:', error)
        message.error('提交失败: ' + (error.message || '请稍后重试'))
      }
      return
    }

    const recordId = currentTakingPaper.value.recordId || currentTakingPaper.value.id
    if (!recordId) {
      message.error('缺少考试记录ID')
      return
    }

    const questions = currentTakingPaper.value.questions || []
    const paperId = currentTakingPaper.value.paperId || ''

    // 按 4.9 规范构建完整答案 payload：包含 studentAnswer / content / maxScore
    const formattedAnswers = questions.map(q => {
      const raw = q.studentAnswer
      const qType = q.type
      const qId = q.questionId || q.id

      let answer
      if (qType === 'true_false') {
        if (typeof raw === 'boolean') {
          answer = raw ? 'true' : 'false'
        } else if (typeof raw === 'string') {
          const u = raw.trim().toUpperCase()
          answer = (u === 'T' || u === 'TRUE' || u === '正确' || u === '对') ? 'true' : 'false'
        } else {
          answer = 'false'
        }
      } else if (qType === 'multiple_choice' || qType === 'fill_blank') {
        if (Array.isArray(raw)) {
          answer = raw.filter(v => v !== '' && v !== null && v !== undefined)
        } else if (typeof raw === 'string' && raw.trim()) {
          answer = raw.split(',').map(s => s.trim()).filter(Boolean)
        } else {
          answer = []
        }
      } else {
        if (raw == null || raw === undefined) {
          answer = ''
        } else if (typeof raw === 'string') {
          answer = raw.trim()
        } else {
          answer = String(raw).trim()
        }
      }

      // 构建题目内容对象（后端批改需要）
      const optionsData = (q.options || []).map(opt => ({
        key: opt.key || opt.label || '',
        content: opt.content || opt.text || ''
      }))
      const questionContent = {
        stem: q.stem || '',
        data: { options: optionsData },
        answer: q.answer || ''
      }

      return {
        questionId: qId,
        questionType: qType,
        answer,
        studentAnswer: raw,           // 原始值，确保后端能存储用户作答
        maxScore: q.maxScore || q.score || 5,
        questionContent: questionContent
      }
    }).filter(a => a.questionId && a.questionType)

    // 诊断：输出每题原始 studentAnswer 值，确认用户是否真的作了答
    console.log('[提交] 📋 每题作答状态:')
    questions.forEach((q, idx) => {
      const raw = q.studentAnswer
      const qid = q.questionId || q.id
      const hasAnswer = raw != null && raw !== '' &&
        !(Array.isArray(raw) && raw.length === 0)
      console.log(`  [${idx + 1}] ID=${(qid || '').substring(0, 8)} type=${q.type} studentAnswer=${JSON.stringify(raw)} ${hasAnswer ? '✅已答' : '❌未答'}`)
    })

    console.log('[提交] 当前考试数据 keys:', Object.keys(currentTakingPaper.value).join(','))
    console.log('[提交] 发送 recordId:', recordId, 'paperId:', paperId, '答案数:', formattedAnswers.length)
    console.log('[提交] 首项完整结构:', JSON.stringify(formattedAnswers[0])?.substring(0, 200))
    console.log('[提交] 完整答案列表:', JSON.stringify(formattedAnswers.map(a => ({
      questionId: a.questionId,
      questionType: a.questionType,
      answer: a.answer,
      studentAnswer: a.studentAnswer,
      hasContent: !!a.questionContent?.stem
    }))))

    const isBlankSubmission = formattedAnswers.length === 0 || formattedAnswers.every(a => {
      const ans = a.answer
      if (Array.isArray(ans)) return ans.length === 0
      return ans == null || ans === ''
    })
    if (isBlankSubmission) {
      console.log('[提交] ⚠️ 空白试卷提交 — recordId:', recordId, '总题数:', questions.length)
    }

    const _logFullError = (label, err) => {
      console.error(`[提交] ${label} 失败:`)
      console.error(`  message: ${err.message}`)
      if (err.response) {
        console.error(`  HTTP状态: ${err.response.status} ${err.response.statusText}`)
        console.error(`  响应数据:`, JSON.stringify(err.response.data))
        console.error(`  响应头:`, JSON.stringify(err.response.headers))
        if (err.config) {
          console.error(`  请求URL: ${err.config.baseURL || ''}${err.config.url || ''}`)
          console.error(`  请求方法: ${err.config.method}`)
        }
        return
      }
      const orig = err.originalError || err
      const resp = orig.response
      if (resp) {
        console.error(`  HTTP状态: ${resp.status} ${resp.statusText}`)
        console.error(`  响应数据:`, JSON.stringify(resp.data))
        console.error(`  响应头:`, JSON.stringify(resp.headers))
        if (orig.config) {
          console.error(`  请求URL: ${orig.config.baseURL || ''}${orig.config.url || ''}`)
          console.error(`  请求方法: ${orig.config.method}`)
        }
      } else if (orig.request) {
        console.error(`  无HTTP响应(request.readyState=${orig.request.readyState})`)
        console.error(`  可能原因: 网络中断/CORS/请求超时`)
      } else {
        const errType = err.constructor?.name || typeof err
        console.error(`  业务错误(type=${errType}): ${err.message?.substring(0, 500)}`)
        if (err.stack) {
          const stackLines = err.stack.split('\n').slice(1, 4).join('\n')
          console.error(`  调用栈:`, stackLines)
        }
      }
    }

    try {
      // 使用 4.9 规范：通用接口 + answerType=formal_exam + recordId（完整格式，含 studentAnswer/content/maxScore）
      console.log('[提交] 调用 /exam/grade (4.9 通用接口, formal_exam) ...')
      const response = await examAPI.gradeAnswers({
        type: 'formal_exam',
        requestId: `formal_${recordId}`,
        recordId,
        paperId,
        answers: formattedAnswers
      })
      console.log('[提交] ✅ 提交成功, 响应:', JSON.stringify(response)?.substring(0, 500))
      message.success('提交成功')

      const respTitle = currentTakingPaper.value?.title || '已提交试卷'
      const respPaperId = currentTakingPaper.value?.paperId || paperId
      const respScore = response?.totalScore != null ? Number(response.totalScore) : (response?.score != null ? Number(response.score) : null)
      const respMaxScore = response?.totalMaxScore != null ? Number(response.totalMaxScore) : (response?.maxScore != null ? Number(response.maxScore) : null)
      const respScoreRate = response?.scoreRate ?? response?.score_rate ?? null
      const respTimeSpent = response?.timeSpent ?? response?.time_spent ?? null
      const respSubmitTime = response?.submitTime ?? response?.submittedAt ?? response?.completedAt ?? new Date().toISOString()

      _pendingSubmitResult = {
        recordId,
        paperId: respPaperId,
        paperTitle: respTitle,
        totalScore: respScore,
        totalMaxScore: respMaxScore,
        scoreRate: respScoreRate,
        timeSpent: respTimeSpent,
        submitTime: respSubmitTime,
        status: 'graded'
      }

      _addToBlacklist(recordId, 'graded', respTitle, respScore)
      currentTakingPaper.value = null
      loadPendingPapers()
      loadExamResults()
      examTab.value = 'results'
    } catch (err) {
      const submittedRecordId = recordId
      const submittedTitle = currentTakingPaper.value?.title || ''
      _logFullError('gradeAnswers(4.9 formal_exam)', err)
      const origErr = err?.originalError || err
      const response = origErr?.response || err?.response
      const statusText = response ? ` (HTTP ${response.status})` : ''
      const backendMsg = response?.data?.message || response?.data?.msg || err?.message || ''
      const isAiServiceError = backendMsg.includes('调用AI服务失败') || backendMsg.includes('GRADE_ERROR') || backendMsg.includes('NoneType')
      const detail = backendMsg ? `: ${backendMsg}` : (err?.code === 'EXAM_NETWORK' ? '（网络连接失败）' : statusText)

      if (isAiServiceError) {
        message.info('AI批改服务暂不可用，记录已提交，可前往成绩单查看状态')
      } else {
        message.error('提交失败' + detail)
      }

      _addToBlacklist(submittedRecordId, isAiServiceError ? 'graded' : 'failed', submittedTitle)
      currentTakingPaper.value = null
      loadPendingPapers()
      loadExamResults()
      examTab.value = 'results'
    }
  }

  const loadExamResults = async () => {
    examTab.value = 'results'
    loading.value = true
    _cleanOldBlacklist()

    let apiCount = 0
    let blCount = 0
    let pendingCount = 0

    try {
      const response = await examAPI.getResults()
      const rawData = Array.isArray(response)
        ? response
        : (response?.list || response?.data || response?.records || response?.items || [])
      apiCount = rawData.length
      if (rawData.length > 0) {
        const statuses = [...new Set(rawData.map(r => r.status || r.examStatus || r.paperStatus || r.state || 'none'))]
        const afterFilter = rawData.filter(r => {
          const s = (r.status || r.examStatus || r.paperStatus || r.state || '').toLowerCase()
          return !s || !_EXCLUDED_STATUSES.includes(s)
        })
        console.log('[成绩单诊断] 后端返回字段:', Object.keys(rawData[0]))
        console.log('[成绩单诊断] 状态分布:', statuses, `(原始${rawData.length}条, 过滤后${afterFilter.length}条)`)
        console.log('[成绩单诊断] 第一条记录:', JSON.stringify(rawData[0], null, 2))
      }
      completedResults.value = rawData
        .filter(r => {
          const s = (r.status || r.examStatus || r.paperStatus || r.state || '').toLowerCase()
          if (!s) return true
          return !_EXCLUDED_STATUSES.includes(s)
        })
        .map(r => {
          // 后端 scoreRate 已是百分比(如85表示85%)，直接取整即可；fallback 用 totalScore/totalMaxScore*100
          let acc = 0
          if (r.scoreRate != null && Number(r.scoreRate) > 0) {
            acc = Math.round(Number(r.scoreRate))
          } else if (r.totalScore != null && Number(r.totalScore) > 0) {
            const max = Number(r.totalMaxScore || r.total_max_score || 100)
            acc = max > 0 ? Math.round((Number(r.totalScore) / max) * 100) : 0
          }
          console.log('[成绩单] 映射:', { id: r.recordId, scoreRate: r.scoreRate, totalScore: r.totalScore, totalMaxScore: r.totalMaxScore, computedAccuracy: acc })

          return {
            ...r,
            id: r.recordId || r.id,
            recordId: r.recordId || r.id,
            paperId: r.paperId || r.paper_id,
            answerType: r.answerType || r.answer_type || 'formal_exam',
            paperTitle: r.paperTitle || r.paperName || '试卷',
            score: r.totalScore != null ? Number(r.totalScore) : (r.score != null ? Number(r.score) : 0),
            totalMaxScore: r.totalMaxScore || r.total_max_score || 100,
            accuracy: acc,
            timeUsed: r.timeSpent != null ? Math.floor(Number(r.timeSpent) / 60) : (r.duration || 0),
            completedAt: r.submitTime || r.completedAt || r.submittedAt || r.updatedAt || ''
          }
        })

    } catch (error) {
      console.warn('加载成绩单失败:', error.message || error)
      completedResults.value = []
    }

    const existingIds = new Set(completedResults.value.map(r => r.recordId || r.id))
    const bl = _loadBlacklist()
    const now = Date.now()
    const BL_MAX_AGE = 30 * 60 * 1000
    let skippedOldBl = 0
    for (const entry of bl) {
      try {
        const parsed = JSON.parse(entry)
        const blId = parsed.id
        const blStatus = parsed.status
        const blTitle = parsed.title || ''
        const blTs = parsed.ts || 0
        const blScore = parsed.score != null ? Number(parsed.score) : null

        if (blStatus !== 'graded' && blStatus !== 'completed') continue
        if (existingIds.has(blId)) continue

        if (now - blTs > BL_MAX_AGE) {
          skippedOldBl++
          continue
        }

        completedResults.value.push({
          id: blId,
          recordId: blId,
          paperId: '',
          answerType: 'formal_exam',
          paperTitle: blTitle || '已提交试卷',
          score: blScore != null ? blScore : 0,
          totalMaxScore: null,
          accuracy: blScore != null ? Math.round((blScore / 100) * 100) : 0,
          timeUsed: 0,
          completedAt: new Date(blTs).toLocaleString(),
          status: blStatus,
          _source: 'blacklist'
        })
        existingIds.add(blId)
        blCount++
      } catch {}
    }

    const pData = _pendingSubmitResult
    _pendingSubmitResult = null
    if (pData && !completedResults.value.some(r => (r.recordId || r.id) === pData.recordId)) {
      completedResults.value.unshift({
        id: pData.recordId,
        recordId: pData.recordId,
        paperId: pData.paperId || '',
        answerType: 'formal_exam',
        paperTitle: pData.paperTitle || '已提交试卷',
        score: pData.totalScore != null ? Number(pData.totalScore) : 0,
        totalMaxScore: Number(pData.totalMaxScore || 100),
        accuracy: pData.scoreRate != null
          ? Math.round(Number(pData.scoreRate) * 100)
          : (pData.totalScore != null
            ? Math.round((Number(pData.totalScore) / Number(pData.totalMaxScore || 100)) * 100)
            : 0),
        timeUsed: pData.timeSpent != null ? Math.floor(Number(pData.timeSpent) / 60) : 0,
        completedAt: pData.submitTime || new Date().toLocaleString(),
        status: pData.status || 'graded',
        _source: 'pendingSubmit'
      })
      pendingCount = 1
    }

    console.log(`[成绩单汇总] API:${apiCount}条 | 黑名单补充:${blCount}条(跳过过期:${skippedOldBl}条) | 提交缓存:${pendingCount}条 | 最终:${completedResults.value.length}条`)
    if (completedResults.value.length > 0) {
      console.log('[成绩单汇总] 记录ID:', completedResults.value.map(r => `${r.recordId || r.id}(${r._source || 'api'})`).join(', '))
    }

    loading.value = false
  }

  const computeIsCorrect = (studentAnswer, correctAnswer, questionType) => {
    const OBJECTIVE_TYPES = ['single_choice', 'multiple_choice', 'true_false']
    const SUBJECTIVE_TYPES = ['subjective', 'essay', 'short_answer']
    if (!studentAnswer || !correctAnswer) return null
    if (String(studentAnswer).trim() === '' || String(correctAnswer).trim() === '') return null
    const qType = String(questionType || '').toLowerCase()
    if (SUBJECTIVE_TYPES.includes(qType)) {
      return null
    }
    const s = String(studentAnswer).trim().toUpperCase().replace(/[\s\u3000]+/g, ' ')
    const c = String(correctAnswer).trim().toUpperCase().replace(/[\s\u3000]+/g, ' ')
    if (Array.isArray(studentAnswer)) {
      const sa = studentAnswer.map(x => String(x).trim().toUpperCase()).sort().join(',')
      const ca = Array.isArray(correctAnswer) ? correctAnswer.map(x => String(x).trim().toUpperCase()).sort().join(',') : c
      return sa === ca || sa.includes(ca.replace(/[\[\]\'\"\s]/g, ''))
    }
    if (s === 'T' || s === 'TRUE') return (c === 'T' || c === 'TRUE' || c === '正确')
    if (s === 'F' || s === 'FALSE') return (c === 'F' || c === 'FALSE' || c === '错误')
    if (qType === 'fill_blank') {
      return s === c || s.includes(c) || c.includes(s) || s.replace(/[，。、；：！？""''（）【】《》\.\,\;\:\!\?\(\)\[\]]/g, '') === c.replace(/[，。、；：！？""''（）【】《》\.\,\;\:\!\?\(\)\[\]]/g, '')
    }
    return s === c
  }

  const viewExamDetail = async (recordId, paperId) => {
    if (!recordId) {
      message.warning('缺少考试记录ID')
      return
    }
    examDetailLoading.value = true
    examDetailError.value = ''
    examTab.value = 'detail'
    examDetailData.value = null

    try {
      console.log('[考试详情] 开始获取 - recordId:', recordId, 'paperId:', paperId)

      let scoreData = null
      let userAnswerData = null
      let paperQuestions = null

      const fetchWithLog = async (label, fn) => {
        try {
          const result = await fn()
          console.log(`[考试详情] ${label} 成功:`, result ? `有数据` : `空数据`)
          return result
        } catch (e) {
          console.warn(`[考试详情] ${label} 失败:`, e.message)
          return null
        }
      }

      // ===== 第一优先：获取考试记录详情（包含完整答案数据）=====
      const adminRecordData = await fetchWithLog('getAdminExamRecordDetail(主源)', () => examAPI.getAdminExamRecordDetail(recordId))

      // ===== 第二优先：获取正式考试成绩（含每题得分和答案）=====
      scoreData = await fetchWithLog('getFormalExamResult', () => examAPI.getFormalExamResult(recordId))
      if (!scoreData) {
        scoreData = await fetchWithLog('getExamResult', () => examAPI.getExamResult(recordId))
      }

      // ===== 第三优先：按记录ID查询用户答题数据（而非按试卷ID）=====
      if (!adminRecordData) {
        userAnswerData = await fetchWithLog('queryUserAnswers(record_id)', () => examAPI.queryUserAnswers({ record_id: recordId }))
        // 回退：按试卷ID查询
        if (!userAnswerData && paperId) {
          userAnswerData = await fetchWithLog('queryUserAnswers(paper_id)', () => examAPI.queryUserAnswers({ paper_id: paperId }))
        }
      } else {
        // adminRecordData 本身就是完整的用户答题数据，直接使用
        userAnswerData = adminRecordData
        console.log('[考试详情] 使用 adminRecordData 作为 userAnswerData')
      }

      // ===== 获取试卷题目列表 =====
      if (paperId) {
        paperQuestions = await fetchWithLog('getPaperDetail', () => examAPI.getPaperDetail(paperId))
        if (!paperQuestions && !paperQuestions?.questions) {
          console.log('[考试详情] getPaperDetail 失败, 回退到 getAdminPaperDetail ...')
          paperQuestions = await fetchWithLog('getAdminPaperDetail(回退)', () => examAPI.getAdminPaperDetail(paperId))
        }
      }

      console.log('[考试详情] 数据收集完成:', {
        hasAdminRecord: !!adminRecordData,
        hasScoreData: !!scoreData,
        hasUserAnswerData: !!userAnswerData,
        hasPaperQuestions: !!paperQuestions,
        adminRecordKeys: adminRecordData ? Object.keys(adminRecordData) : [],
        scoreKeys: scoreData ? Object.keys(scoreData) : [],
        userAnswerKeys: userAnswerData ? Object.keys(userAnswerData) : [],
        paperQuestionKeys: paperQuestions ? Object.keys(paperQuestions) : []
      })

      // 详细诊断：输出 adminRecordData 的完整结构
      if (adminRecordData) {
        console.log('[考试详情] 🔍 adminRecordData 完整结构:', JSON.stringify(adminRecordData, null, 2)?.substring(0, 2000))
        // 检查 questions 字段
        if (adminRecordData.questions && Array.isArray(adminRecordData.questions)) {
          console.log('[考试详情] 🔍 adminRecordData.questions 数量:', adminRecordData.questions.length)
          if (adminRecordData.questions[0]) {
            console.log('[考试详情] 🔍 adminRecordData.questions[0] 所有key:', Object.keys(adminRecordData.questions[0]))
            console.log('[考试详情] 🔍 adminRecordData.questions[0] 结构:', JSON.stringify(adminRecordData.questions[0], null, 2)?.substring(0, 800))
          }
        }
      }

      const rawAnswers = []
      // 从 scoreData 提取答案
      if (scoreData?.answers) {
        const sAnswers = Array.isArray(scoreData.answers) ? scoreData.answers : []
        rawAnswers.push(...sAnswers)
        if (sAnswers.length > 0) {
          console.log('[考试详情] scoreData.answers[0] 完整结构:', JSON.stringify(sAnswers[0], null, 2)?.substring(0, 500))
          console.log('[考试详情] scoreData.answers[0] 所有key:', Object.keys(sAnswers[0]))
        }
      }

      // 从 userAnswerData（含adminRecordData）提取答案
      if (userAnswerData?.answers) {
        const uAnswers = Array.isArray(userAnswerData.answers) ? userAnswerData.answers : []
        rawAnswers.push(...uAnswers)
        if (uAnswers.length > 0) {
          console.log('[考试详情] userAnswerData.answers[0] 完整结构:', JSON.stringify(uAnswers[0], null, 2)?.substring(0, 500))
        }
      }
      // 从 userAnswerData.questions 提取每题的答案信息（adminRecordData 可能以 questions 形式返回更丰富的数据）
      if (userAnswerData?.questions && Array.isArray(userAnswerData.questions)) {
        const uq = Array.isArray(userAnswerData.questions) ? userAnswerData.questions : []
        console.log('[考试详情] userAnswerData.questions 数量:', uq.length)
        if (uq.length > 0) {
          console.log('[考试详情] userAnswerData.questions[0] 所有key:', Object.keys(uq[0]))
          // 将每个 question 转换为 answer 格式，补充到 rawAnswers
          uq.forEach(q => {
            const qid = q.questionId || q.question_id || q.id
            if (!qid) return
            // 检查该 question 是否已有答案数据（避免重复）
            const existingIdx = rawAnswers.findIndex(a =>
              (a.questionId || a.question_id || a.id) === qid
            )
            const answerObj = {
              questionId: qid,
              // 学生答案字段（多种可能名称）
              userAnswer: q.userAnswer ?? q.studentAnswer ?? q.student_answer ?? q.submittedAnswer ?? null,
              // 正确答案字段
              correctAnswer: q.correctAnswer ?? q.correct_answer ?? q.answer ?? q.standardAnswer ?? null,
              // 分数字段
              score: q.score ?? q.gotScore ?? q.got_score ?? null,
              maxScore: q.maxScore ?? q.max_score ?? q.fullScore ?? null,
              isCorrect: q.isCorrect ?? q.is_correct ?? null,
              feedback: q.feedback ?? '',
              // 题目内容
              content: q.content || {},
              stem: q.stem || '',
              options: q.options || [],
              questionType: q.questionType || q.question_type || q.type || ''
            }
            if (existingIdx >= 0) {
              // 合并：用 question 的丰富数据补充已有的 sparse answer
              const existing = rawAnswers[existingIdx]
              Object.keys(answerObj).forEach(k => {
                if (answerObj[k] != null && (existing[k] == null || existing[k] === '')) {
                  existing[k] = answerObj[k]
                }
              })
            } else {
              rawAnswers.push(answerObj)
            }
          })
          console.log('[考试详情] 从 userAnswerData.questions 补充后 rawAnswers 总数:', rawAnswers.length)
        }
      }

      // 额外：从 adminRecordData 的其他可能字段提取
      if (adminRecordData && !rawAnswers.length) {
        for (const key of ['answerList', 'question_answers', 'resultAnswers', 'gradedAnswers', 'submittedAnswers']) {
          if (Array.isArray(adminRecordData[key])) {
            rawAnswers.push(...adminRecordData[key])
            console.log(`[考试详情] 从 adminRecordData.${key} 提取 ${adminRecordData[key].length} 条`)
            break
          }
        }
      }

      const answersMap = {}
      rawAnswers.forEach(a => {
        const qid = a.questionId || a.question_id || a.question_id || a.id
        if (!qid) {
          console.warn('[考试详情] 跳过无ID的answer:', Object.keys(a))
          return
        }
        if (!answersMap[qid]) {
          answersMap[qid] = {}
        }

        let aContent = a.questionContent || a.question_content || a.content || answersMap[qid].content || {}
        if (typeof aContent === 'string') {
          try { aContent = JSON.parse(aContent) } catch (e) { aContent = { raw: aContent } }
        }
        if (aContent === null || aContent === undefined) aContent = {}

        const extractedStem = a.stem || a.question_stem || a.title || a.questionTitle || ''
        if (extractedStem && !aContent.stem) {
          aContent = { ...aContent, stem: extractedStem }
        }

        const extractedOptions = a.options || a.optionList || a.choices || []
        if (extractedOptions.length > 0 && !aContent.options && !aContent.data?.options) {
          aContent = { ...aContent, data: { ...(aContent.data || {}), options: extractedOptions } }
        }

        // Python None 序列化为字符串 "None" 的处理
        const _stripNone = (v) => {
          if (v === null || v === undefined) return ''
          const s = String(v).trim()
          if (!s || s.toLowerCase() === 'none' || s.toLowerCase() === 'null') return ''
          return s
        }

        const extractedCorrect = _stripNone(a.correctAnswer) || _stripNone(a.correct_answer) || _stripNone(a.rightAnswer) || _stripNone(a.standard_answer) || _stripNone(aContent?.answer) || ''
        let rawStudent = a.userAnswer ?? a.user_answer ?? a.studentAnswer ?? a.student_answer ?? a.myAnswer ?? a.submittedAnswer ?? null
        const extractedStudent = _stripNone(rawStudent)

        const rawFeedbackText = a.feedback || a.comment || a.remark || ''
        let correctFromFb = ''
        if (rawFeedbackText && !extractedCorrect) {
          const m = rawFeedbackText.match(/(?:正确答案|答案|标准答案)[:：]\s*(.+)/)
          if (m) correctFromFb = _stripNone(m[1].trim())
        }

        Object.assign(answersMap[qid], {
          questionId: qid,
          questionType: a.questionType || a.question_type || a.type || answersMap[qid].questionType || '',
          studentAnswer: extractedStudent,
          correctAnswer: extractedCorrect || correctFromFb,
          score: a.score ?? a.studentScore ?? a.got_score ?? answersMap[qid].score ?? 0,
          maxScore: a.maxScore ?? a.max_score ?? a.totalScore ?? a.full_score ?? answersMap[qid].maxScore ?? null,
          isCorrect: a.isCorrect ?? a.is_correct ?? a.correct ?? a.isRight ?? answersMap[qid].isCorrect ?? null,
          feedback: rawFeedbackText,
          content: aContent,
          stem: extractedStem || answersMap[qid].stem || ''
        })
      })

      // 从数据库查询用户提交的答案（替代本地缓存）
      console.log('[考试详情] 🔍 调用 queryUserAnswers 查询数据库中的用户答案, recordId:', recordId)
      try {
        const userAnswerRes = await examAPI.queryUserAnswers({
          record_id: recordId,
          answer_type: 'formal_exam'
        })
        console.log('[考试详情] 🔍 queryUserAnswers 返回:', JSON.stringify(userAnswerRes)?.substring(0, 500))

        // 解析返回的用户答案数据
        let dbAnswers = []
        if (Array.isArray(userAnswerRes)) {
          dbAnswers = userAnswerRes
        } else if (userAnswerRes?.answers && Array.isArray(userAnswerRes.answers)) {
          dbAnswers = userAnswerRes.answers
        } else if (userAnswerRes?.data) {
          dbAnswers = Array.isArray(userAnswerRes.data) ? userAnswerRes.data : (userAnswerRes.data?.answers || [])
        }

        if (dbAnswers.length > 0) {
          let restoredCount = 0
          dbAnswers.forEach(dbAns => {
            const qid = dbAns.questionId || dbAns.question_id
            if (!qid || !answersMap[qid]) return

            // 从多个可能的字段名提取用户答案
            let rawStudent = dbAns.student_answer ?? dbAns.studentAnswer ?? dbAns.user_answer ?? dbAns.answer ?? null
            let restored = ''
            if (typeof rawStudent === 'boolean') {
              restored = rawStudent ? 'true' : 'false'
            } else if (Array.isArray(rawStudent)) {
              restored = rawStudent.length > 0 ? rawStudent : ''
            } else if (rawStudent != null && rawStudent !== undefined && String(rawStudent).trim()) {
              restored = String(rawStudent).trim()
            }
            if (restored) {
              answersMap[qid].studentAnswer = restored
              restoredCount++
            }
          })
          console.log(`[考试详情] ✅ 从数据库恢复 ${restoredCount} 题的用户答案`)
        } else {
          console.log('[考试详情] ⚠️ queryUserAnswers 返回空数据，无用户答案记录')
        }
      } catch (queryErr) {
        console.warn('[考试详情] ⚠️ queryUserAnswers 查询失败:', queryErr.message)
      }

      console.log('[考试详情] answersMap构建完成, 条数:', Object.keys(answersMap).length)
      if (Object.keys(answersMap).length > 0) {
        const firstKey = Object.keys(answersMap)[0]
        console.log(`[考试详情] answersMap[${firstKey}] 预览:`, {
          stem: (answersMap[firstKey].stem || '').substring(0, 60),
          correctAnswer: String(answersMap[firstKey].correctAnswer),
          studentAnswer: String(answersMap[firstKey].studentAnswer),
          contentKeys: Object.keys(answersMap[firstKey].content || {}),
          hasContentStem: !!(answersMap[firstKey].content?.stem),
          contentStemPreview: (answersMap[firstKey].content?.stem || '').substring(0, 60)
        })
      }

      // 从 paperQuestions 的题目中提取正确答案（试卷详情可能包含每题的答案）
      if (paperQuestions?.questions && Array.isArray(paperQuestions.questions)) {
        console.log('[考试详情] 🔍 检查 paperQuestions.questions 是否含答案数据...')
        paperQuestions.questions.forEach((pq, idx) => {
          const qid = pq.questionId || pq.question_id || pq.id
          if (!qid) return
          // 从题目 content 中提取 answer
          const pqContent = pq.content || {}
          const contentAnswer = pqContent?.answer
            || pqContent?.data?.answer
            || (typeof pqContent === 'string' ? (() => { try { return JSON.parse(pqContent)?.answer } catch { return null } })() : null)
          // 从题目顶层字段提取
          const topAnswer = pq.correctAnswer || pq.correct_answer || pq.answer || pq.standardAnswer

          const mergedAnswer = topAnswer || contentAnswer
          if (mergedAnswer && qid && answersMap[qid]) {
            const existing = answersMap[qid]
            if (!existing.correctAnswer || existing.correctAnswer === '' || existing.correctAnswer === 'None') {
              console.log(`[考试详情] 🔍 从 paperQuestions.questions[${idx}] 补充 correctAnswer:`, String(mergedAnswer).substring(0, 50))
              existing.correctAnswer = String(mergedAnswer)
            }
          }
        })
      }

      // 最终答案诊断：输出每个题目的最终答案状态
      console.log('[考试详情] ✅ 答案提取最终状态:')
      Object.keys(answersMap).forEach(qid => {
        const a = answersMap[qid]
        console.log(`  [${qid.substring(0, 8)}...] studentAnswer="${a.studentAnswer}" correctAnswer="${a.correctAnswer}" score=${a.score} isCorrect=${a.isCorrect}`)
      })

      const questionList = []
      if (paperQuestions?.questions && Array.isArray(paperQuestions.questions)) {
        questionList.push(...paperQuestions.questions)
      }
      if (userAnswerData?.questions && Array.isArray(userAnswerData.questions)) {
        userAnswerData.questions.forEach(q => {
          const qid = q.questionId || q.question_id
          if (!qid) return
          if (!questionList.some(ex => (ex.questionId || ex.question_id) === qid)) {
            questionList.push(q)
          }
        })
      }

      let questions = []
      if (questionList.length > 0) {
        questions = questionList.map((q, idx) => {
          const qid = q.questionId || q.question_id
          const answer = qid ? (answersMap[qid] || {}) : {}

          let qContent = q.content || q.questionContent || q.question_content || answer.content || {}
          if (typeof qContent === 'string') {
            try { qContent = JSON.parse(qContent) } catch (e) { qContent = { raw: qContent } }
          }
          if (!qContent.stem && answer.stem) {
            qContent = { ...qContent, stem: answer.stem }
          }

          let qOptions = qContent?.data?.options || qContent?.options || q.options || []
          if (qOptions.length === 0 && answer.content?.data?.options) {
            qOptions = answer.content.data.options
          } else if (qOptions.length === 0 && answer.content?.options) {
            qOptions = answer.content.options
          }

          // 提取学生答案：优先从 answersMap，再从 question 本身
          // 支持多种字段名变体（snake_case / camelCase）
          const rawStudent = answer.studentAnswer ?? q.studentAnswer ?? q.userAnswer ?? q.student_answer ?? q.user_answer ?? q.myAnswer ?? q.submittedAnswer ?? ''
          const rawCorrect = answer.correctAnswer ?? q.correctAnswer ?? q.correct_answer ?? q.answer ?? q.standardAnswer ?? q.rightAnswer ?? qContent?.answer ?? q.content?.answer ?? ''
          const qType = q.questionType || q.question_type || answer.questionType || q.type || ''
          const computedCorrect = computeIsCorrect(rawStudent, rawCorrect, qType)

          const rawBackendIsCorrect = answer.isCorrect ?? answer.is_correct ?? answer.correct ?? null
            const finalIsCorrect = (rawBackendIsCorrect === true)
              ? true
              : ((rawBackendIsCorrect === false && computedCorrect === true) ? true : (rawBackendIsCorrect ?? computedCorrect))

            return {
            questionId: qid || `q_${idx}`,
            questionType: q.questionType || q.question_type || answer.questionType || q.type || '',
            content: qContent,
            stem: qContent.stem || q.stem || answer.stem || '',
            options: qOptions,
            studentAnswer: rawStudent,
            correctAnswer: rawCorrect,
            score: answer.score ?? 0,
            maxScore: answer.maxScore ?? q.score ?? answer.totalScore ?? null,
            isCorrect: finalIsCorrect,
            feedback: answer.feedback || q.feedback || ''
          }
        })
      } else {
        questions = Object.values(answersMap).map((a, idx) => {
          let aContent = a.content || {}
          if (typeof aContent === 'string') {
            try { aContent = JSON.parse(aContent) } catch (e) { aContent = { stem: aContent } }
          }
          if (!aContent.stem && a.stem) {
            aContent = { ...aContent, stem: a.stem }
          }

          const rawStudent = a.studentAnswer ?? ''
          const rawCorrect = a.correctAnswer ?? aContent?.answer ?? ''
          const qType = a.questionType || ''
          const computedCorrect = computeIsCorrect(rawStudent, rawCorrect, qType)

          const rawBackendIsCorrect = a.isCorrect ?? null
          const finalIsCorrect = (rawBackendIsCorrect === true)
            ? true
            : ((rawBackendIsCorrect === false && computedCorrect === true) ? true : (rawBackendIsCorrect ?? computedCorrect))

          return {
            questionId: a.questionId || `q_${idx}`,
            questionType: a.questionType || '',
            content: aContent,
            stem: aContent.stem || a.stem || '',
            options: aContent?.data?.options || aContent?.options || [],
            studentAnswer: rawStudent,
            correctAnswer: rawCorrect,
            score: a.score ?? 0,
            maxScore: a.maxScore ?? null,
            isCorrect: finalIsCorrect,
            feedback: a.feedback || ''
          }
        })
      }

      console.log('[考试详情] questions初步构建完成:', questions.length, '条')
      if (questions.length > 0) {
        console.log('[考试详情] 第一题预览:', {
          id: questions[0].questionId,
          type: questions[0].questionType,
          hasStem: !!questions[0].stem,
          stemLen: (questions[0].stem || '').length,
          optionsCount: (questions[0].options || []).length,
          correctAnswer: String(questions[0].correctAnswer),
          studentAnswer: String(questions[0].studentAnswer),
          contentKeys: Object.keys(questions[0].content || {})
        })
      }

      const cachedQuestions = _paperQuestionsCache.get(paperId) || _paperQuestionsCache.get(scoreData?.paperId) || []
      if (cachedQuestions.length > 0) {
        console.log('[考试详情] 📦 发现缓存题目数据, 数量:', cachedQuestions.length)
        const cacheMap = new Map(cachedQuestions.map(cq => [cq.questionId, cq]))
        questions = questions.map(q => {
          const cached = cacheMap.get(q.questionId)
          if (!cached) return q
          console.log(`[考试详情] 📦 缓存命中 ${q.questionId}: stem="${(cached.stem || '').substring(0, 40)}", options=${cached.options?.length || 0}, answer=${JSON.stringify(cached.answer)}`)
          const mergedContent = { ...(q.content || {}), stem: cached.stem }
          if (cached.options?.length > 0 && (!mergedContent.options || !mergedContent.data?.options)) {
            mergedContent.data = { ...mergedContent.data, options: cached.options }
          }
          if (cached.answer && !q.correctAnswer) {
            mergedContent.answer = cached.answer
          }
          return {
            ...q,
            content: mergedContent,
            stem: cached.stem || q.stem || '',
            options: cached.options || q.options || [],
            correctAnswer: q.correctAnswer || cached.answer || mergedContent.answer || '',
            questionType: q.questionType || cached.questionType || '',
            _source: 'cache'
          }
        })
        console.log('[考试详情] 📦 缓存合并完成, 有stem的题目数:', questions.filter(q => !!q.stem).length, '/', questions.length)
      }

      const fullQuestionMap = {}
      const allQuestionIds = new Set(questions.map(q => q.questionId).filter(Boolean))
      rawAnswers.forEach(a => {
        const qid = a.questionId || a.question_id
        if (qid) allQuestionIds.add(qid)
      })

      // 仅对缺少题干/选项的题目进行详情补充请求，避免不必要的 500 错误
      const needsEnrichment = (qid) => {
        const existQ = questions.find(q => q.questionId === qid)
        if (!existQ) return true // 不在列表中的需要获取
        if (!existQ.stem && !existQ.content?.stem) return true // 缺少题干
        if (existQ.questionType === 'single_choice' || existQ.questionType === 'multiple_choice' || existQ.questionType === 'true_false') {
          if (!existQ.options || existQ.options.length === 0) return true // 选择题缺少选项
        }
        return false
      }
      const enrichIds = [...allQuestionIds].filter(needsEnrichment)
      const skipIds = [...allQuestionIds].filter(qid => !needsEnrichment(qid))
      if (skipIds.length > 0) {
        console.log(`[考试详情] 跳过 ${skipIds.length} 个已完整题目的详情请求:`, skipIds)
      }

      console.log('[考试详情] 题目ID汇总 - questions:', questions.length, '条, answersMap:', Object.keys(answersMap).length, '个, 需补充:', enrichIds.length, '跳过:', skipIds.length, '总ID数:', allQuestionIds.size)

      if (enrichIds.length > 0) {
        const idList = enrichIds
        console.log('[考试详情] 开始获取题目详情，共', enrichIds.length, '题, ID列表:', idList)
        console.log('[考试详情] === 进入题目详情获取分支，questionAPI类型:', typeof questionAPI, 'keys:', Object.keys(questionAPI || {}))

        let fullResults = []
        try {
          fullResults = await Promise.all(
            idList.map((qid, idx) => {
              console.log(`[考试详情] map回调触发 [${idx}] qid=`, qid)
              return (async () => {
                try {
                  console.log(`[考试详情] [${idx + 1}/${idList.length}] 准备调用 GET /question/${qid}`)
                  const res = await questionAPI.getQuestionById(qid)
              console.log(`[考试详情] [${idx + 1}/${idList.length}] 题目 ${qid} axios响应收到:`, {
                status: res?.status,
                statusText: res?.statusText,
                hasData: !!res?.data,
                dataType: typeof res?.data,
                dataKeys: res?.data ? Object.keys(res.data).slice(0, 10) : []
              })

              let qData = null
              const payload = res?.data
              if (payload) {
                if (payload.code === 200 && payload.data !== undefined && payload.data !== null) {
                  qData = payload.data
                  console.log(`[考试详情] [${idx + 1}] 标准格式解包: code=200, 取 payload.data`)
                } else if (payload.code === 200 || payload.code === undefined) {
                  qData = payload
                  console.log(`[考试详情] [${idx + 1}] 直接格式: 直接使用 payload`)
                } else {
                  console.warn(`[考试详情] [${idx + 1}] 业务错误 code=${payload.code}:`, payload.message || payload.msg)
                }
              } else {
                console.warn(`[考试详情] [${idx + 1}] payload为空! res=`, JSON.stringify(res)?.substring(0, 200))
              }

              if (qData) {
                console.log(`[考试详情] [${idx + 1}] ✅ 题目 ${qid} 解析成功:`, {
                  keys: Object.keys(qData),
                  hasContent: !!qData.content,
                  contentType: typeof qData.content,
                  hasStem: !!(qData.content?.stem || qData.stem),
                  stemPreview: (qData.content?.stem || qData.stem || '(无)').substring(0, 60),
                  optionsCount: Array.isArray(qData.content?.data?.options) ? qData.content.data.options.length : (Array.isArray(qData.content?.options) ? qData.content.options.length : 0)
                })
              }
              return { questionId: qid, data: qData }
              } catch (e) {
                  console.error(`[考试详情] [${idx + 1}/${idList.length}] ❌ 题目 ${qid} 异常:`, e.message, 'stack:', e.stack?.substring(0, 200))
                  return { questionId: qid, data: null }
                }
              })()
            })
          )
        } catch (outerErr) {
          console.error('[考试详情] 题目详情获取外层异常:', outerErr.message, outerErr.stack?.substring(0, 300))
        }

        console.log('[考试详情] Promise.all 完成, 结果数:', fullResults.length)

        fullResults.forEach(fq => {
          if (fq.data) {
            fullQuestionMap[fq.questionId] = fq.data
          }
        })

        console.log('[考试详情] 题目详情获取完成，成功:', Object.keys(fullQuestionMap).length, '/', enrichIds.length)

        if (Object.keys(fullQuestionMap).length > 0) {
          questions = questions.map(q => {
            const full = fullQuestionMap[q.questionId]
            if (!full || !full.content) {
              console.log(`[考试详情] 合并跳过 ${q.questionId}:`, !full ? '无full数据' : '无content字段')
              return q
            }

            const fullContent = full.content || {}
            const parsedContent = typeof fullContent === 'string'
              ? (() => { try { return JSON.parse(fullContent) } catch { return { stem: fullContent } } })()
              : fullContent

            const mergedContent = { ...q.content, ...parsedContent }
            if (full.stem && !mergedContent.stem) mergedContent.stem = full.stem
            if (parsedContent.answer && !mergedContent.answer) mergedContent.answer = parsedContent.answer
            if (parsedContent.explanation && !mergedContent.explanation) mergedContent.explanation = parsedContent.explanation

            const fullOptions = mergedContent?.data?.options
              || mergedContent?.options
              || full.data?.options
              || full.options
              || q.options
              || []

            const fullAnswer = mergedContent.answer || q.correctAnswer || ''

            console.log(`[考试详情] 合并完成 ${q.questionId}:`, {
              stem: (mergedContent.stem || '').substring(0, 50),
              optionsCount: fullOptions.length,
              correctAnswer: String(fullAnswer),
              hasExplanation: !!mergedContent.explanation
            })

            return {
              ...q,
              content: mergedContent,
              stem: mergedContent.stem || full.stem || q.stem || '',
              options: fullOptions,
              correctAnswer: fullAnswer,
              _hasFullContent: true
            }
          })
        }
      }

      console.log('[考试详情] 最终questions结构预览:', questions.slice(0, 2).map(q => ({
        id: q.questionId,
        type: q.questionType,
        hasStem: !!q.stem,
        stemPreview: (q.stem || '').substring(0, 40),
        optionsCount: (q.options || []).length,
        correctAnswer: String(q.correctAnswer),
        studentAnswer: String(q.studentAnswer),
        hasFullContent: !!q._hasFullContent
      })))

      const merged = scoreData || userAnswerData || paperQuestions || {}
      const apiTotalScore = merged.totalScore != null ? Number(merged.totalScore) : (merged.total_score != null ? Number(merged.total_score) : null)
      const apiTotalMaxScore = merged.totalMaxScore != null ? Number(merged.totalMaxScore) : (merged.total_max_score != null ? Number(merged.total_max_score) : null)
      const apiScoreRate = merged.scoreRate != null ? Number(merged.scoreRate) : (merged.score_rate != null ? Number(merged.score_rate) : null)

      // 严格使用接口返回值计算总分/满分/得分率
      let finalTotalScore = apiTotalScore ?? 0
      let finalTotalMaxScore = apiTotalMaxScore
      let finalScoreRate = apiScoreRate

      // 仅当接口未返回 totalMaxScore 时，才从题目 maxScore 之和回退（并记录警告）
      if (finalTotalMaxScore == null) {
        const sumMaxScore = questions.reduce((s, q) => s + (q.maxScore != null ? Number(q.maxScore) : 0), 0)
        if (sumMaxScore > 0) {
          finalTotalMaxScore = sumMaxScore
          console.warn('[考试详情] ⚠️ 接口未返回totalMaxScore，使用题目maxScore之和:', sumMaxScore)
        } else {
          console.warn('[考试详情] ⚠️ 接口和题目均无maxScore数据')
        }
      }

      // scoreRate：优先接口，其次根据 totalScore/totalMaxScore 计算
      if ((finalScoreRate == null || finalScoreRate === 0) && finalTotalMaxScore > 0 && finalTotalScore > 0) {
        finalScoreRate = Math.round((finalTotalScore / finalTotalMaxScore) * 100) / 100
      }

      const sumScore = questions.reduce((s, q) => s + (q.score != null ? Number(q.score) : 0), 0)
      const sumMaxScore = questions.reduce((s, q) => s + (q.maxScore != null ? Number(q.maxScore) : 0), 0)

      console.log('[考试详情] 分数交叉验证:', {
        '接口totalScore': apiTotalScore,
        '接口totalMaxScore': apiTotalMaxScore,
        '接口scoreRate': apiScoreRate,
        '题目score之和': sumScore,
        '题目maxScore之和': sumMaxScore,
        '最终totalScore': finalTotalScore,
        '最终totalMaxScore': finalTotalMaxScore,
        '最终scoreRate': finalScoreRate
      })

      examDetailData.value = {
        recordId,
        paperId: merged.paperId || merged.paper_id || paperId,
        paperTitle: merged.paperTitle || merged.paper_title || merged.paperName || '考试详情',
        totalScore: finalTotalScore,
        totalMaxScore: finalTotalMaxScore ?? 0,
        scoreRate: finalScoreRate ?? 0,
        submitTime: merged.submitTime || merged.submit_time || merged.completedAt || '',
        questions
      }
      console.log('[考试详情] 最终数据:', {
        totalQuestions: questions.length,
        paperTitle: examDetailData.value.paperTitle,
        totalScore: examDetailData.value.totalScore
      })
    } catch (error) {
      console.error('[考试详情] 整体失败:', error)
      examDetailError.value = error.message || '获取考试详情失败'
      message.error('获取考试详情失败')
    } finally {
      examDetailLoading.value = false
    }
  }

  const closeExamDetail = () => {
    examDetailData.value = null
    examDetailError.value = ''
    examTab.value = 'results'
  }

  return {
    examTab,
    pendingPapers,
    currentTakingPaper,
    completedResults,
    loading,
    examStats,
    examDetailData,
    examDetailLoading,
    examDetailError,
    selftestConfig,
    isGeneratingSelftest,
    isSelfTest,
    loadPendingPapers,
    startExam,
    startSelftest,
    submitExam,
    loadExamResults,
    viewExamDetail,
    closeExamDetail
  }
}