<template>
  <div class="page-container">
    <div class="gen-hero">
      <div class="gen-hero-icon" style="background: var(--gradient-orange)">
        <el-icon :size="28" color="#fff"><Trophy /></el-icon>
      </div>
      <div>
        <h2>教学游戏</h2>
        <p>AI生成闯关、选择、填空等互动练习，学生可以直接在页面作答</p>
      </div>
    </div>

    <div class="gen-input-section">
      <div v-if="quickPromptNotice" class="quick-notice">
        <el-icon><MagicStick /></el-icon>
        <span>{{ quickPromptNotice }}</span>
      </div>
      <div class="prompt-box">
        <el-input
          v-model="form.prompt"
          type="textarea"
          :rows="4"
          placeholder="描述你需要的练习，例如：生成10道初中数学一元二次方程的选择题..."
          resize="none"
        />
        <div class="prompt-footer">
          <div class="prompt-tags">
            <span class="prompt-tag" v-for="t in suggestions" :key="t" @click="form.prompt = t">{{ t }}</span>
          </div>
          <button class="tpl-btn" type="button" @click="showTemplateGallery = true">
            <el-icon><Files /></el-icon>
            <span>用模板</span>
          </button>
          <button class="gen-btn" style="background: var(--gradient-orange)" :disabled="!form.prompt || generating" @click="handleGenerate">
            <el-icon v-if="!generating"><MagicStick /></el-icon>
            <span v-if="generating" class="btn-loading"></span>
            {{ generating ? 'AI生成中...' : '生成游戏' }}
          </button>
        </div>
      </div>
      <div class="material-row">
        <MaterialPicker v-model="selectedMaterials" />
      </div>
      <div class="settings-row">
        <div class="setting-item">
          <label>练习类型</label>
          <el-select v-model="form.exercise_type" size="default">
            <el-option label="选择题" value="choice" />
            <el-option label="填空题" value="fill_blank" />
            <el-option label="判断题" value="true_false" />
            <el-option label="匹配题" value="matching" />
            <el-option label="排序拖拽" value="drag_sort" />
            <el-option label="贪吃蛇闯关" value="game_snake" />
            <el-option label="翻牌配对" value="game_match" />
            <el-option label="冒险闯关" value="game_adventure" />
          </el-select>
        </div>
        <div class="setting-item">
          <label>学科</label>
          <el-input v-model="form.subject" placeholder="学科" size="default" style="width: 120px" />
        </div>
        <div class="setting-item">
          <label>题数</label>
          <el-input-number v-model="form.count" :min="1" :max="50" size="default" />
        </div>
      </div>
    </div>

    <div v-if="generating" class="loading-section">
      <div class="loading-bar"><div class="loading-bar-fill"></div></div>
      <p>AI正在生成练习题...</p>
            <p style="font-size:13px;color:var(--text-secondary);opacity:.65;margin-top:10px">模型深度推理中，通常需要 1-2 分钟，请耐心等待</p>
    </div>

    <div v-else-if="!result" class="guide-section">
      <div class="capability-row">
        <div v-for="item in capabilities" :key="item.title">
          <strong>{{ item.title }}</strong>
          <span>{{ item.desc }}</span>
        </div>
      </div>
      <div class="guide-cards">
        <div class="guide-card" v-for="g in guideExamples" :key="g.title" @click="form.prompt = g.prompt">
          <div class="guide-icon" :style="{ background: g.bg }">
            <el-icon :size="18" color="#fff"><component :is="g.icon" /></el-icon>
          </div>
          <div class="guide-info">
            <h4>{{ g.title }}</h4>
            <p>{{ g.prompt }}</p>
          </div>
          <span class="guide-arrow">试试 →</span>
        </div>
      </div>
    </div>

    <div v-if="result" class="result-section">
      <div class="result-header">
        <div>
          <h3>{{ result.title }}</h3>
          <span class="result-meta">共 {{ result.questions?.length || 0 }} 题 · {{ typeLabel(form.exercise_type) }}</span>
        </div>
        <div class="header-actions">
          <button class="mode-btn" :class="{ active: viewMode === 'interactive' }" @click="viewMode = 'interactive'">
            <el-icon><Monitor /></el-icon> 互动
          </button>
          <button class="mode-btn" :class="{ active: viewMode === 'detail' }" @click="viewMode = 'detail'">
            <el-icon><List /></el-icon> 详情
          </button>
          <button class="mode-btn" @click="reuseCurrent">
            <el-icon><MagicStick /></el-icon> 用它生成
          </button>
          <button class="mode-btn publish" :disabled="publishing" @click="publishCurrent">
            <el-icon><Share /></el-icon> {{ publishing ? '发布中' : '发布资源' }}
          </button>
          <button class="save-btn" style="background: var(--gradient-orange)" @click="handleSave"><el-icon><Check /></el-icon> 保存练习</button>
          <button class="mode-btn" @click="downloadCurrent"><el-icon><Download /></el-icon> 下载Word</button>
        </div>
      </div>

      <!-- Interactive Mode: answer questions and get feedback -->
      <div v-if="viewMode === 'interactive' && result.questions?.length" class="interactive-mode">
        <!-- Score bar -->
        <div class="quiz-score-bar">
          <span>第 {{ currentQIdx + 1 }} / {{ result.questions.length }} 题</span>
          <span v-if="answeredCount > 0">已答 {{ answeredCount }} · 正确 {{ correctCount }} · 正确率 {{ scorePercent }}%</span>
          <span v-if="attemptSummary" class="attempt-summary">已有 {{ attemptSummary.count }} 人完成 · 平均正确率 {{ attemptSummary.avgScore }}%</span>
          <button v-if="answeredCount > 0" type="button" class="reset-btn" @click="resetQuiz">重新作答</button>
        </div>

        <!-- Question -->
        <div class="quiz-question-card">
          <div class="quiz-q-header">
            <span class="q-num">{{ currentQIdx + 1 }}</span>
            <el-tag size="small" effect="plain">{{ currentQuestion.type || form.exercise_type }}</el-tag>
          </div>
          <MarkdownContent :content="currentQuestion.question" class="q-text" />
          <div v-if="currentQuestion.html" class="quiz-html-preview">
            <HtmlPreview :html="currentQuestion.html" height="280px" />
          </div>

          <!-- Choice / True-False: option buttons -->
          <div v-if="currentQuestion.options?.length" class="quiz-options">
            <button
              v-for="(opt, oi) in currentQuestion.options"
              :key="oi"
              type="button"
              class="quiz-option"
              :class="optionClass(oi)"
              :disabled="isRevealed(currentQIdx)"
              @click="selectOption(opt)"
            >
              <span class="opt-letter">{{ String.fromCharCode(65 + oi) }}</span>
              <span>{{ opt }}</span>
              <el-icon v-if="isRevealed(currentQIdx) && opt === currentQuestion.answer" class="opt-correct"><CircleCheckFilled /></el-icon>
              <el-icon v-else-if="isRevealed(currentQIdx) && opt === getUserAnswer(currentQIdx) && opt !== currentQuestion.answer" class="opt-wrong"><CircleCloseFilled /></el-icon>
            </button>
          </div>

          <!-- Fill-blank: text input -->
          <div v-else class="quiz-fill-input">
            <input
              v-model="fillAnswer"
              type="text"
              class="fill-input"
              placeholder="输入你的答案..."
              :disabled="isRevealed(currentQIdx)"
              @keyup.enter="submitFillAnswer"
            />
            <button v-if="!isRevealed(currentQIdx)" type="button" class="submit-answer-btn" @click="submitFillAnswer">提交答案</button>
          </div>

          <!-- Feedback after answering -->
          <div v-if="isRevealed(currentQIdx)" class="quiz-feedback" :class="{ correct: isCurrentCorrect, wrong: !isCurrentCorrect }">
            <div class="feedback-head">
              <el-icon v-if="isCurrentCorrect" :size="20"><CircleCheckFilled /></el-icon>
              <el-icon v-else :size="20"><CircleCloseFilled /></el-icon>
              <strong>{{ isCurrentCorrect ? '回答正确！' : '回答错误' }}</strong>
              <span v-if="!isCurrentCorrect">正确答案：{{ currentQuestion.answer }}</span>
            </div>
            <div v-if="currentQuestion.explanation" class="feedback-explain">
              <MarkdownContent :content="currentQuestion.explanation" />
            </div>
          </div>
        </div>

        <!-- Navigation -->
        <div class="interactive-nav">
          <button class="nav-btn" :disabled="currentQIdx <= 0" @click="currentQIdx--">
            <el-icon><ArrowLeft /></el-icon>
          </button>
          <div class="nav-dots">
            <span
              v-for="(q, idx) in result.questions"
              :key="idx"
              class="dot"
              :class="{
                active: currentQIdx === idx,
                correct: isRevealed(idx) && isCorrect(idx),
                wrong: isRevealed(idx) && !isCorrect(idx),
              }"
              @click="currentQIdx = idx"
            >{{ idx + 1 }}</span>
          </div>
          <button class="nav-btn" :disabled="currentQIdx >= result.questions.length - 1" @click="currentQIdx++">
            <el-icon><ArrowRight /></el-icon>
          </button>
        </div>
      </div>

      <!-- Detail Mode: show all questions -->
      <div v-if="viewMode === 'detail'" class="detail-mode">
        <div v-for="(q, idx) in result.questions" :key="idx" class="question-card">
          <div class="q-header">
            <span class="q-num">{{ idx + 1 }}</span>
            <el-tag size="small" effect="plain">{{ q.type }}</el-tag>
            <el-tag v-if="q.difficulty" size="small" effect="plain" :type="q.difficulty === 'easy' ? 'success' : q.difficulty === 'hard' ? 'danger' : 'warning'">
              {{ q.difficulty === 'easy' ? '简单' : q.difficulty === 'hard' ? '困难' : '中等' }}
            </el-tag>
          </div>
          <MarkdownContent :content="q.question" class="q-text" />
          <div v-if="q.html" class="q-preview">
            <HtmlPreview :html="q.html" height="300px" />
          </div>
          <div v-if="q.options" class="q-options">
            <div v-for="(opt, oi) in q.options" :key="oi" class="q-option" :class="{ correct: opt === q.answer }">
              <span class="opt-letter">{{ String.fromCharCode(65 + oi) }}</span>
              <span>{{ opt }}</span>
            </div>
          </div>
          <div class="q-answer">
            <el-icon :size="14" color="#10B981"><Check /></el-icon>
            <span>答案：{{ q.answer }}</span>
          </div>
          <div v-if="q.explanation" class="q-explanation"><MarkdownContent :content="q.explanation" /></div>
        </div>
      </div>
    </div>

    <section class="saved-section">
      <div class="saved-header">
        <div>
          <h3>已保存练习</h3>
          <p>保存后的课堂练习会出现在这里，方便二次打开和管理</p>
        </div>
        <button class="refresh-btn" type="button" @click="loadSavedExercises">
          <el-icon><Refresh /></el-icon>
          刷新
        </button>
      </div>
      <div v-if="savedLoading" class="saved-loading">正在加载已保存练习...</div>
      <div v-else-if="savedExercises.length === 0" class="saved-empty">
        <el-icon><Trophy /></el-icon>
        <span>暂无已保存练习</span>
      </div>
      <div v-else class="saved-grid">
        <article v-for="item in savedExercises" :key="item.id" class="saved-card">
          <div class="saved-cover">
            <el-icon><Trophy /></el-icon>
            <strong>{{ item.title }}</strong>
            <span>{{ typeLabel(item.exercise_type) }} · {{ item.questions?.length || 0 }}题</span>
          </div>
          <div class="saved-body">
            <h4>{{ item.title }}</h4>
            <p>{{ item.subject || '未设置学科' }} · {{ item.knowledge_points?.join('、') || '未设置知识点' }}</p>
            <div class="saved-actions">
              <button type="button" @click="previewSaved(item)"><el-icon><View /></el-icon>预览</button>
              <button type="button" @click="publishSaved(item)"><el-icon><Share /></el-icon>发布</button>
              <button type="button" @click="downloadSaved(item)"><el-icon><Download /></el-icon>下载</button>
              <el-popconfirm title="确定删除这个练习？关联资源会同步下架。" @confirm="handleDeleteSaved(item.id)">
                <template #reference>
                  <button type="button" class="danger"><el-icon><Delete /></el-icon>删除</button>
                </template>
              </el-popconfirm>
            </div>
          </div>
        </article>
      </div>

    <TemplateGallery v-model="showTemplateGallery" kind="game" @use="handleUseTemplate" />
    </section>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive, computed, onMounted, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import { aiGenerateExercise, createExercise, deleteExercise, exportExerciseDocx, getExercise, getExercises, getExerciseAttempts, submitExerciseAttempt, updateExercise } from '@/api/exercise'
import { publishResource } from '@/api/resource'
import MarkdownContent from '@/components/common/MarkdownContent.vue'
import HtmlPreview from '@/components/common/HtmlPreview.vue'
import TemplateGallery from '@/components/common/TemplateGallery.vue'
import MaterialPicker from '@/components/common/MaterialPicker.vue'
import { useUserStore } from '@/stores/user'
import { downloadBlob } from '@/utils/download'
import { buildMaterialPromptBlock, type MaterialContextItem } from '@/utils/materialContext'

const router = useRouter()
const route = useRoute()
const userStore = useUserStore()
const generating = ref(false)
const result = ref<any>(null)
const savedLoading = ref(false)
const savedExercises = ref<any[]>([])
const quickPromptNotice = ref('')
const viewMode = ref<'interactive' | 'detail'>('interactive')
const currentQIdx = ref(0)
const userAnswers = reactive<Record<number, string>>({})
const revealedSet = reactive<Set<number>>(new Set())
const fillAnswer = ref('')
const attemptRecorded = ref(false)
const attemptSummary = ref<{ count: number; avgScore: number } | null>(null)

const answeredCount = computed(() => Object.keys(userAnswers).length)
const correctCount = computed(() => [...revealedSet].filter(idx => isCorrect(idx)).length)
const scorePercent = computed(() => answeredCount.value > 0 ? Math.round((correctCount.value / answeredCount.value) * 100) : 0)
const isCurrentCorrect = computed(() => isCorrect(currentQIdx.value))

watch(currentQIdx, () => {
  fillAnswer.value = isRevealed(currentQIdx.value) ? getUserAnswer(currentQIdx.value) : ''
})

watch(answeredCount, (n) => {
  const total = result.value?.questions?.length || 0
  if (total > 0 && n >= total) recordAttempt()
})
const savedResultId = ref<number | null>(null)
const publishing = ref(false)
const selectedMaterials = ref<MaterialContextItem[]>([])
const showTemplateGallery = ref(false)
const suggestions = ['一元二次方程选择题', '英语语法填空题', '历史知识判断题']
const guideExamples = [
  { title: '数学选择题', prompt: '生成10道初中数学一元二次方程的选择题，难度中等，包含详细解析', icon: 'Trophy', bg: 'var(--gradient-orange)' },
  { title: '英语语法填空', prompt: '生成8道英语语法填空题，考查时态和语态的用法', icon: 'MagicStick', bg: 'var(--gradient-green)' },
  { title: '历史知识判断', prompt: '生成15道中国古代史判断题，涵盖秦汉至明清', icon: 'Flag', bg: 'var(--gradient-blue)' },
]
const capabilities = [
  { title: '即时作答', desc: '生成可直接在页面完成的互动题目' },
  { title: '答案解析', desc: '每道题保留答案、难度和解析说明' },
  { title: '课堂复用', desc: '保存后可按题型和知识点再次打开' },
]
const form = reactive({ prompt: '', exercise_type: 'choice', subject: '', count: 5, knowledge_points: [] as string[] })

const currentQuestion = computed(() => {
  if (!result.value?.questions?.length) return { answer: '', explanation: '', html: '' }
  return result.value.questions[currentQIdx.value] || { answer: '', explanation: '', html: '' }
})

function getUserAnswer(idx: number): string {
  return userAnswers[idx] || ''
}

function isRevealed(idx: number): boolean {
  return revealedSet.has(idx)
}

function isCorrect(idx: number): boolean {
  if (!isRevealed(idx)) return false
  const q = result.value?.questions?.[idx]
  if (!q) return false
  const ua = String(userAnswers[idx] || '').trim().toLowerCase()
  const ca = String(q.answer || '').trim().toLowerCase()
  return ua === ca
}

function selectOption(opt: string) {
  if (isRevealed(currentQIdx.value)) return
  userAnswers[currentQIdx.value] = opt
  revealedSet.add(currentQIdx.value)
}

function submitFillAnswer() {
  if (isRevealed(currentQIdx.value)) return
  const ans = fillAnswer.value.trim()
  if (!ans) return
  userAnswers[currentQIdx.value] = ans
  revealedSet.add(currentQIdx.value)
}

function optionClass(oi: number): string {
  if (!isRevealed(currentQIdx.value)) return ''
  const opt = currentQuestion.value.options?.[oi] || ''
  if (opt === currentQuestion.value.answer) return 'is-correct'
  if (opt === getUserAnswer(currentQIdx.value) && opt !== currentQuestion.value.answer) return 'is-wrong'
  return 'is-dimmed'
}

function resetQuiz() {
  recordAttempt()
  Object.keys(userAnswers).forEach(k => delete userAnswers[Number(k)])
  revealedSet.clear()
  fillAnswer.value = ''
  currentQIdx.value = 0
  attemptRecorded.value = false
}

async function recordAttempt() {
  if (attemptRecorded.value || answeredCount.value === 0 || !savedResultId.value) return
  const total = result.value?.questions?.length || 0
  attemptRecorded.value = true
  try {
    await submitExerciseAttempt(savedResultId.value, {
      answers: Object.entries(userAnswers).map(([idx, ans]) => ({ q: Number(idx) + 1, a: ans })),
      score: correctCount.value,
      total: total || answeredCount.value,
    })
  } catch {
    attemptRecorded.value = false
  }
}

function handleUseTemplate(payload: { kind: string; template: any; params: Record<string, any>; html: string; title: string }) {
  result.value = {
    title: payload.title,
    questions: [{
      question: payload.template.name || '教学游戏',
      html: payload.html,
      answer: '',
      explanation: payload.template.description || '',
      options: [],
      difficulty: '简单',
    }],
  }
  savedResultId.value = null
  resetQuiz()
  const catMap: Record<string, string> = {
    game_snake: 'game_snake', game_match: 'game_match', game_adventure: 'game_adventure',
    drag_sort: 'drag_sort', matching: 'matching', memory: 'game_match',
  }
  if (payload.template.category && catMap[payload.template.category]) {
    form.exercise_type = catMap[payload.template.category]
  }
  ElMessage.success('已应用模板，可直接预览或保存')
}

async function handleGenerate() {
  if (!(await ensureLoggedIn())) return
  generating.value = true
  currentQIdx.value = 0
  resetQuiz()
  try {
    const res: any = await aiGenerateExercise({
      ...form,
      prompt: buildPromptWithMaterials(form.prompt),
    })
    userStore.refreshCreditsFromResponse(res)
    result.value = res.data
    savedResultId.value = null
    ElMessage.success('练习生成成功')
  } catch (e: any) {
    if (handleAuthError(e)) return
    ElMessage.error('生成失败：' + (e.response?.data?.detail || e.message || ''))
  }
  finally { generating.value = false }
}

function buildPromptWithMaterials(prompt: string) {
  return `${prompt}${buildMaterialPromptBlock(selectedMaterials.value, '参考素材')}`.trim()
}

async function handleSave() {
  if (!result.value) return
  if (!(await ensureLoggedIn())) return
  const payload = {
    title: result.value.title,
    exercise_type: form.exercise_type,
    subject: form.subject,
    knowledge_points: form.knowledge_points,
    questions: result.value.questions,
  }
  const isUpdate = !!savedResultId.value
  const saved: any = isUpdate
    ? await updateExercise(savedResultId.value!, payload)
    : await createExercise(payload)
  const item = saved.data || saved
  savedResultId.value = item?.id || null
  ElMessage.success(isUpdate ? '练习已更新' : '练习已保存')
  await loadSavedExercises()
}

async function downloadCurrent() {
  const id = await ensureSavedCurrent()
  if (id) await downloadSaved({ id, title: result.value?.title || '课堂练习' })
}

async function downloadSaved(item: any) {
  if (!(await ensureLoggedIn())) return
  try {
    const blob = await exportExerciseDocx(item.id)
    downloadBlob(blob, `${safeFilename(item.title || '课堂练习')}-练习.docx`)
    ElMessage.success('已开始下载')
  } catch (e: any) {
    ElMessage.error('下载失败：' + (e.response?.data?.detail || e.message || ''))
  }
}

async function loadSavedExercises() {
  if (!(await ensureLoggedIn({ silent: true }))) {
    savedExercises.value = []
    savedLoading.value = false
    return
  }
  savedLoading.value = true
  try {
    const res: any = await getExercises({ limit: 50 })
    savedExercises.value = res.data || res || []
  } catch (e: any) {
    if (handleAuthError(e)) {
      savedExercises.value = []
      return
    }
    ElMessage.error('加载已保存练习失败：' + (e.response?.data?.detail || e.message || ''))
  } finally {
    savedLoading.value = false
  }
}

async function previewSaved(item: any) {
  result.value = {
    title: item.title,
    questions: item.questions || [],
  }
  savedResultId.value = item.id
  form.exercise_type = item.exercise_type || 'choice'
  form.subject = item.subject || ''
  form.knowledge_points = item.knowledge_points || []
  currentQIdx.value = 0
  viewMode.value = 'interactive'
  attemptSummary.value = null
  attemptRecorded.value = false
  window.scrollTo({ top: 0, behavior: 'smooth' })
  try {
    const attempts: any = await getExerciseAttempts(item.id)
    if (Array.isArray(attempts) && attempts.length > 0) {
      const avg = Math.round(attempts.reduce((s: number, a: any) => s + (a.total > 0 ? (a.score / a.total) * 100 : 0), 0) / attempts.length)
      attemptSummary.value = { count: attempts.length, avgScore: avg }
    }
  } catch { /* ignore */ }
}

async function handleDeleteSaved(id: number) {
  if (!(await ensureLoggedIn())) return
  await deleteExercise(id)
  ElMessage.success('练习已删除，关联资源已下架')
  await loadSavedExercises()
}

async function ensureSavedCurrent() {
  if (!result.value) return null
  if (!(await ensureLoggedIn())) return null
  const payload = {
    title: result.value.title || '课堂练习',
    exercise_type: form.exercise_type,
    subject: form.subject,
    knowledge_points: form.knowledge_points,
    questions: result.value.questions || [],
  }
  const saved: any = savedResultId.value
    ? await updateExercise(savedResultId.value, payload)
    : await createExercise(payload)
  const item = saved.data || saved
  savedResultId.value = item?.id || null
  await loadSavedExercises()
  return savedResultId.value
}

async function publishCurrent() {
  if (!result.value) return
  publishing.value = true
  try {
    const id = await ensureSavedCurrent()
    if (!id) return
    await publishExerciseAsset({
      id,
      title: result.value.title || '课堂练习',
      exercise_type: form.exercise_type,
      subject: form.subject,
      knowledge_points: form.knowledge_points,
      questions: result.value.questions || [],
    })
  } finally {
    publishing.value = false
  }
}

async function publishSaved(item: any) {
  if (!(await ensureLoggedIn())) return
  await publishExerciseAsset(item)
}

async function publishExerciseAsset(item: any) {
  const created: any = await publishResource({
    resource_type: 'exercise',
    title: item.title,
    description: buildExerciseDescription(item),
    content_ref: `exercise:${item.id}`,
    file_url: '',
    tags: ['教学游戏', typeLabel(item.exercise_type), ...(item.knowledge_points || []).slice(0, 3)],
    subject: item.subject || '',
    grade: '',
    is_public: 1,
  })
  const resource = created.data || created
  ElMessage.success('已发布到资源广场')
  if (resource?.id) router.push(`/resources/${resource.id}`)
}

function buildExerciseDescription(item: any) {
  const points = item.knowledge_points?.length ? `，覆盖${item.knowledge_points.join('、')}` : ''
  return `${item.subject || '通用'}${typeLabel(item.exercise_type)}课堂练习，共${item.questions?.length || 0}题${points}，支持互动预览、答案解析和二次改编。`
}

function reuseCurrent() {
  if (!result.value) return
  localStorage.setItem('quick_create_prompt', `参考练习《${result.value.title || '课堂练习'}》，重新生成一套原创教学游戏。要求保留核心知识点，优化题目梯度、即时反馈和解析。`)
  result.value = null
  savedResultId.value = null
  window.scrollTo({ top: 0, behavior: 'smooth' })
}

async function ensureLoggedIn(options: { silent?: boolean } = {}) {
  if (!userStore.isLoggedIn()) {
    if (!options.silent) ElMessage.warning('请先登录后再使用教学游戏功能')
    await router.push('/login')
    return false
  }
  if (!userStore.user) {
    try {
      await userStore.fetchProfile()
    } catch {
      if (!options.silent) ElMessage.warning('登录状态失效，请重新登录')
      await router.push('/login')
      return false
    }
  }
  return true
}

function isAuthError(error: any) {
  return error?.response?.status === 401 ||
    (error?.response?.status === 403 && error?.response?.data?.detail === 'Not authenticated')
}

function handleAuthError(error: any) {
  if (!isAuthError(error)) return false
  userStore.clearToken()
  ElMessage.warning('登录状态失效，请重新登录')
  router.push('/login')
  return true
}

function typeLabel(type: string) {
  const map: Record<string, string> = {
    choice: '选择题',
    fill_blank: '填空题',
    true_false: '判断题',
    matching: '匹配题',
    drag_sort: '排序拖拽',
    game_snake: '贪吃蛇闯关',
    game_match: '翻牌配对',
    game_adventure: '冒险闯关',
  }
  return map[type] || '练习'
}

function safeFilename(value: string) {
  return (value || '资源').replace(/[\\/:*?"<>|\r\n]+/g, '_').trim() || '资源'
}

onMounted(async () => {
  const quickPrompt = localStorage.getItem('quick_create_prompt')
  if (quickPrompt) {
    form.prompt = quickPrompt
    form.subject = inferSubject(quickPrompt)
    form.exercise_type = inferExerciseType(quickPrompt)
    form.count = inferCount(quickPrompt)
    quickPromptNotice.value = '已带入首页游戏/练习指令，可直接生成或继续调整题型。'
    localStorage.removeItem('quick_create_prompt')
  }
  await loadSavedExercises()
  await openSavedFromRoute()
})

async function openSavedFromRoute() {
  const openId = Number(route.query.open)
  if (!Number.isFinite(openId) || openId <= 0) return
  try {
    const data: any = await getExercise(openId)
    const item = data.data || data
    previewSaved(item)
  } catch {
    ElMessage.warning('未能打开改编后的练习')
  }
}

function inferSubject(text: string) {
  const subjects = ['数学', '英语', '语文', '物理', '化学', '历史', '信息科技']
  return subjects.find(item => text.includes(item)) || ''
}

function inferExerciseType(text: string) {
  if (/填空/.test(text)) return 'fill_blank'
  if (/判断|对错/.test(text)) return 'true_false'
  if (/匹配|连线/.test(text)) return 'matching'
  return 'choice'
}

function inferCount(text: string) {
  const match = text.match(/(\d+)\s*道/)
  const count = match ? Number(match[1]) : 5
  return Number.isFinite(count) ? Math.min(Math.max(count, 1), 50) : 5
}
</script>

<style scoped>
.gen-hero { display: flex; align-items: center; gap: 16px; margin-bottom: 24px; }
.gen-hero-icon { width: 52px; height: 52px; border-radius: 14px; display: flex; align-items: center; justify-content: center; }
.gen-hero h2 { font-size: 24px; font-weight: 700; color: var(--text-primary); }
.gen-hero p { font-size: 14px; color: var(--text-muted); }

.gen-input-section { background: #fff; border: 1px solid var(--border-color); border-radius: var(--radius-lg); padding: 24px; margin-bottom: 24px; }
.quick-notice { min-height: 38px; display: flex; align-items: center; gap: 8px; border: 1px solid #dce8de; border-radius: 12px; background: #f0fbef; color: #00543d; padding: 8px 12px; margin-bottom: 14px; font-size: 13px; font-weight: 800; }
.prompt-box { margin-bottom: 16px; }
.prompt-box :deep(.el-textarea__inner) { border: none; background: #F8FAFC; border-radius: var(--radius-md); padding: 16px; font-size: 15px; line-height: 1.6; }
.prompt-footer { display: flex; justify-content: space-between; align-items: center; margin-top: 12px; }
.prompt-tags { display: flex; gap: 8px; }
.prompt-tag { padding: 4px 12px; background: #FFFBEB; color: #F59E0B; border-radius: 20px; font-size: 12px; cursor: pointer; transition: all 0.2s; }
.prompt-tag:hover { background: #F59E0B; color: #fff; }
.material-row { display: flex; flex-wrap: wrap; gap: 8px; padding: 14px 0 0; margin-top: 4px; border-top: 1px solid var(--border-color); }
.tpl-btn { display: inline-flex; align-items: center; gap: 6px; height: 40px; padding: 0 16px; border: 1px solid #fed7aa; border-radius: var(--radius-sm); background: #fff; color: #c2410c; cursor: pointer; font-size: 14px; font-weight: 600; transition: all 0.2s; }
.tpl-btn:hover { border-color: #ea580c; background: #fff7ed; }
.gen-btn { display: flex; align-items: center; gap: 8px; border: none; color: #fff; padding: 10px 28px; border-radius: var(--radius-sm); font-size: 15px; font-weight: 600; cursor: pointer; transition: all 0.3s; }
.gen-btn:hover:not(:disabled) { opacity: 0.9; transform: translateY(-1px); }
.gen-btn:disabled { opacity: 0.5; cursor: not-allowed; }
.settings-row { display: flex; gap: 24px; align-items: center; padding-top: 16px; border-top: 1px solid var(--border-color); }
.setting-item { display: flex; align-items: center; gap: 8px; }
.setting-item label { font-size: 13px; color: var(--text-muted); white-space: nowrap; }

.loading-section { text-align: center; padding: 48px 0; }
.loading-bar { width: 300px; height: 4px; background: #E2E8F0; border-radius: 2px; margin: 0 auto 20px; overflow: hidden; }
.loading-bar-fill { height: 100%; width: 40%; background: var(--gradient-orange); border-radius: 2px; animation: loadingSlide 1.5s ease-in-out infinite; }
@keyframes loadingSlide { 0% { transform: translateX(-100%); } 100% { transform: translateX(350%); } }
.loading-section p { font-size: 14px; color: var(--text-secondary); }

.guide-section { animation: fadeIn 0.4s ease; }
.capability-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; margin-bottom: 14px; }
.capability-row div { min-height: 78px; border: 1px solid #eadfcb; border-radius: 12px; background: #fff; padding: 14px 16px; }
.capability-row strong { display: block; color: #9a5f00; font-size: 15px; margin-bottom: 6px; }
.capability-row span { color: #7a6850; font-size: 12px; line-height: 1.45; }
.guide-cards { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; }
.guide-card { display: flex; flex-direction: column; gap: 10px; background: #fff; border: 1px solid var(--border-color); border-radius: var(--radius-md); padding: 18px; cursor: pointer; transition: all 0.3s; }
.guide-card:hover { box-shadow: var(--shadow-md); border-color: #F59E0B; transform: translateY(-2px); }
.guide-icon { width: 36px; height: 36px; border-radius: 10px; display: flex; align-items: center; justify-content: center; }
.guide-info h4 { font-size: 14px; font-weight: 600; color: var(--text-primary); margin-bottom: 4px; }
.guide-info p { font-size: 12px; color: var(--text-muted); line-height: 1.5; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.guide-arrow { font-size: 12px; color: #F59E0B; font-weight: 500; margin-top: auto; }

.result-section { animation: fadeInUp 0.5s ease; }
.result-header { display: flex; justify-content: space-between; align-items: flex-start; gap: 16px; margin-bottom: 20px; }
.result-header h3 { font-size: 20px; font-weight: 600; color: var(--text-primary); margin-bottom: 4px; }
.result-meta { font-size: 13px; color: var(--text-muted); }
.header-actions { display: flex; align-items: center; justify-content: flex-end; gap: 8px; flex-wrap: wrap; }
.mode-btn { display: flex; align-items: center; gap: 4px; padding: 6px 14px; border: 1px solid var(--border-color); border-radius: var(--radius-sm); background: #fff; font-size: 13px; color: var(--text-secondary); cursor: pointer; transition: all 0.2s; }
.mode-btn.active { background: #FFF7ED; border-color: #F59E0B; color: #F59E0B; }
.mode-btn:hover { border-color: #F59E0B; }
.mode-btn.publish { border-color: #f59e0b; color: #9a5f00; font-weight: 800; }
.mode-btn:disabled { opacity: .58; cursor: not-allowed; }
.save-btn { display: flex; align-items: center; gap: 6px; border: none; color: #fff; padding: 8px 20px; border-radius: var(--radius-sm); font-size: 14px; font-weight: 500; cursor: pointer; transition: opacity 0.2s; }
.save-btn:hover { opacity: 0.9; }

/* Interactive Mode */
.interactive-mode { }
.interactive-stage { background: #F1F5F9; border-radius: var(--radius-lg); padding: 24px; margin-bottom: 16px; }
.interactive-stage :deep(.html-preview) { border-radius: var(--radius-md); box-shadow: 0 4px 24px rgba(0,0,0,0.08); }
.interactive-nav { display: flex; align-items: center; justify-content: center; gap: 16px; margin-bottom: 16px; }
.nav-btn { width: 40px; height: 40px; border-radius: 50%; border: 1px solid var(--border-color); background: #fff; display: flex; align-items: center; justify-content: center; cursor: pointer; transition: all 0.2s; }
.nav-btn:hover:not(:disabled) { border-color: #F59E0B; color: #F59E0B; }
.nav-btn:disabled { opacity: 0.3; cursor: not-allowed; }
.nav-dots { display: flex; gap: 6px; flex-wrap: wrap; justify-content: center; }
.dot { width: 32px; height: 32px; border-radius: 8px; border: 1px solid var(--border-color); display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 600; color: var(--text-muted); cursor: pointer; transition: all 0.2s; }
.dot.active { background: var(--gradient-orange); border-color: transparent; color: #fff; }
.dot:hover:not(.active) { border-color: #F59E0B; }
.interactive-answer { background: #F8FAFC; border: 1px solid var(--border-color); border-radius: var(--radius-md); padding: 16px; }
.quiz-score-bar { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 10px 16px; border-radius: 10px; background: #f0fdf4; border: 1px solid #dce8de; margin-bottom: 14px; font-size: 13px; font-weight: 700; color: #00543d; flex-wrap: wrap; }
.quiz-score-bar .reset-btn { border: 1px solid #dbe8de; border-radius: 8px; background: #fff; color: #00543d; padding: 4px 12px; font-size: 12px; cursor: pointer; font-weight: 700; }
.quiz-score-bar .attempt-summary { color: #6b7f76; font-weight: 600; font-size: 12px; padding: 2px 10px; background: #fff; border-radius: 6px; border: 1px solid #e2ece4; }
.quiz-question-card { background: #fff; border: 1px solid var(--border-color); border-radius: 14px; padding: 20px; margin-bottom: 16px; }
.quiz-q-header { display: flex; align-items: center; gap: 8px; margin-bottom: 12px; }
.quiz-html-preview { margin: 12px 0; border-radius: 10px; overflow: hidden; border: 1px solid var(--border-color); }
.quiz-options { display: flex; flex-direction: column; gap: 8px; margin-top: 14px; }
.quiz-option { display: flex; align-items: center; gap: 10px; padding: 12px 16px; border: 2px solid var(--border-color); border-radius: 10px; background: #fff; cursor: pointer; transition: all 0.2s; font-size: 14px; text-align: left; }
.quiz-option:hover:not(:disabled) { border-color: #F59E0B; background: #fffbeb; }
.quiz-option .opt-letter { width: 28px; height: 28px; border-radius: 50%; background: #f1f5f9; display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 13px; color: var(--text-muted); flex-shrink: 0; }
.quiz-option.is-correct { border-color: #10B981; background: #ecfdf5; }
.quiz-option.is-correct .opt-letter { background: #10B981; color: #fff; }
.quiz-option.is-wrong { border-color: #EF4444; background: #fef2f2; }
.quiz-option.is-wrong .opt-letter { background: #EF4444; color: #fff; }
.quiz-option.is-dimmed { opacity: 0.5; }
.quiz-option:disabled { cursor: default; }
.opt-correct { color: #10B981; margin-left: auto; }
.opt-wrong { color: #EF4444; margin-left: auto; }
.quiz-fill-input { display: flex; gap: 8px; margin-top: 14px; }
.fill-input { flex: 1; height: 42px; border: 2px solid var(--border-color); border-radius: 10px; padding: 0 14px; font-size: 14px; outline: none; }
.fill-input:focus { border-color: #F59E0B; }
.fill-input:disabled { background: #f8fafc; }
.submit-answer-btn { height: 42px; padding: 0 18px; border: none; border-radius: 10px; background: #F59E0B; color: #fff; font-weight: 700; cursor: pointer; }
.quiz-feedback { margin-top: 16px; border-radius: 10px; padding: 14px 16px; }
.quiz-feedback.correct { background: #ecfdf5; border: 1px solid #a7f3d0; }
.quiz-feedback.wrong { background: #fef2f2; border: 1px solid #fecaca; }
.feedback-head { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; font-size: 14px; }
.feedback-head strong { font-size: 15px; }
.quiz-feedback.correct .feedback-head { color: #065f46; }
.quiz-feedback.wrong .feedback-head { color: #991b1b; }
.feedback-explain { padding-top: 8px; border-top: 1px solid rgba(0,0,0,0.06); font-size: 13px; line-height: 1.6; }
.dot.correct { background: #10B981; border-color: transparent; color: #fff; }
.dot.wrong { background: #EF4444; border-color: transparent; color: #fff; }
.answer-explain { margin-top: 8px; font-size: 13px; color: var(--text-muted); line-height: 1.6; }

/* Detail Mode */
.detail-mode { display: flex; flex-direction: column; gap: 16px; }
.question-card { background: #fff; border: 1px solid var(--border-color); border-radius: var(--radius-md); padding: 20px; transition: all 0.3s; }
.question-card:hover { box-shadow: var(--shadow-md); }
.q-header { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; }
.q-num { width: 28px; height: 28px; background: var(--gradient-orange); border-radius: 8px; display: flex; align-items: center; justify-content: center; color: #fff; font-size: 13px; font-weight: 700; }
.q-text { font-size: 15px; line-height: 1.7; color: var(--text-primary); margin-bottom: 14px; }
.q-preview { margin-bottom: 14px; border-radius: var(--radius-sm); overflow: hidden; }
.q-options { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-bottom: 14px; }
.q-option { display: flex; align-items: center; gap: 8px; padding: 10px 14px; border: 1px solid var(--border-color); border-radius: var(--radius-sm); font-size: 14px; transition: all 0.2s; }
.q-option.correct { border-color: #10B981; background: #ECFDF5; color: #059669; }
.opt-letter { width: 22px; height: 22px; background: #F1F5F9; border-radius: 6px; display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 600; color: var(--text-secondary); flex-shrink: 0; }
.q-option.correct .opt-letter { background: #10B981; color: #fff; }
.q-answer { display: flex; align-items: center; gap: 6px; color: #10B981; font-size: 14px; font-weight: 500; }
.q-explanation { margin-top: 10px; padding: 10px 14px; background: #F8FAFC; border-radius: var(--radius-sm); font-size: 13px; color: var(--text-muted); line-height: 1.6; }

.btn-loading { width: 16px; height: 16px; border: 2px solid rgba(255,255,255,0.3); border-top-color: #fff; border-radius: 50%; animation: spin 0.6s linear infinite; }

.saved-section { margin-top: 28px; background: #fff; border: 1px solid var(--border-color); border-radius: var(--radius-lg); padding: 22px; }
.saved-header { display: flex; justify-content: space-between; align-items: flex-start; gap: 16px; margin-bottom: 18px; }
.saved-header h3 { font-size: 18px; font-weight: 700; color: var(--text-primary); margin-bottom: 4px; }
.saved-header p { font-size: 13px; color: var(--text-muted); }
.refresh-btn { height: 34px; display: inline-flex; align-items: center; gap: 6px; border: 1px solid #eadfcb; border-radius: 17px; background: #fff; color: #9a5f00; padding: 0 14px; font-weight: 700; cursor: pointer; }
.saved-loading,
.saved-empty { min-height: 120px; display: flex; align-items: center; justify-content: center; gap: 8px; color: var(--text-muted); border: 1px dashed #eadfcb; border-radius: var(--radius-md); background: #fffaf0; }
.saved-empty .el-icon { font-size: 24px; color: #d89a2a; }
.saved-grid { display: grid; grid-template-columns: repeat(3, minmax(220px, 1fr)); gap: 16px; }
.saved-card { overflow: hidden; border: 1px solid #eadfcb; border-radius: 12px; background: #fff; }
.saved-cover { height: 132px; display: flex; flex-direction: column; justify-content: center; gap: 8px; margin: 5px; padding: 18px; border-radius: 9px; color: #fff; background: linear-gradient(135deg, #c2410c, #f59e0b); }
.saved-cover .el-icon { font-size: 22px; opacity: .85; }
.saved-cover strong { font-size: 18px; line-height: 1.25; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.saved-cover span { width: fit-content; padding: 3px 8px; border-radius: 12px; background: rgba(255,255,255,.2); font-size: 12px; font-weight: 800; }
.saved-body { padding: 12px 16px 16px; }
.saved-body h4 { font-size: 15px; color: var(--text-primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-bottom: 6px; }
.saved-body p { min-height: 36px; color: var(--text-muted); font-size: 12px; line-height: 1.5; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.saved-actions { display: flex; gap: 8px; margin-top: 12px; }
.saved-actions button { height: 32px; display: inline-flex; align-items: center; justify-content: center; gap: 5px; border: 1px solid #eadfcb; border-radius: 8px; background: #fffaf0; color: #9a5f00; padding: 0 12px; cursor: pointer; font-weight: 700; }
.saved-actions .danger:hover { border-color: #fca5a5; background: #fef2f2; color: #ef4444; }

@media (max-width: 1080px) {
  .saved-grid { grid-template-columns: repeat(2, minmax(220px, 1fr)); }
}

@media (max-width: 760px) {
  .prompt-footer,
  .settings-row,
  .result-header,
  .saved-header,
  .header-actions { flex-direction: column; align-items: stretch; }
  .capability-row,
  .guide-cards,
  .saved-grid,
  .q-options { grid-template-columns: 1fr; }
}
</style>
