<script setup lang="ts">
import { computed, onMounted, ref, watch } from 'vue'
import { useRouter } from 'vue-router'
import QuizCard from '../components/QuizCard.vue'
import SpellCard from '../components/SpellCard.vue'
import WordGraphCanvas from '../components/WordGraphCanvas.vue'
import { api, type MemoryGraphLink, type MemoryGraphNode, type QuizQuestion, type Word } from '../api/request'
import { buildPracticeQuestion, type PracticeMode } from '../utils/buildPracticeQuestion'
import {
  buildPracticeGraphLinks,
  buildPracticeGraphNodes,
  resolvePracticeDisplayIds,
} from '../utils/practiceGraphDisplay'
import {
  getGraphPracticeDisplayIds,
  getGraphPracticeWordIds,
  isPracticeSessionComplete,
  loadPracticeResults,
  savePracticeResult,
  type PracticeResult,
} from '../utils/practiceGraphSession'
import { submitQuizAnswer } from '../composables/useQuizSession'
import { useQuizTimer } from '../composables/useQuizTimer'

const router = useRouter()
const { startQuestionTimer, consumeDurationSeconds } = useQuizTimer()

const modes: { key: PracticeMode; label: string }[] = [
  { key: 'en_to_zh', label: '看英文选中文' },
  { key: 'zh_to_en', label: '看中文选英文' },
  { key: 'spell', label: '拼写' },
]

const loading = ref(true)
const wordPool = ref<Word[]>([])
const words = ref<Word[]>([])
const graphNodes = ref<MemoryGraphNode[]>([])
const graphLinks = ref<MemoryGraphLink[]>([])
const wordIds = ref<string[]>([])
const practiceResults = ref<Record<string, PracticeResult>>({})
const practiceMode = ref<PracticeMode>('zh_to_en')
const queueIndex = ref(0)
const selected = ref('')
const submittedAnswer = ref('')
const showResult = ref(false)
const isCorrect = ref(false)
const spellCardRef = ref<InstanceType<typeof SpellCard> | null>(null)

const sessionComplete = computed(() =>
  isPracticeSessionComplete(wordIds.value, practiceResults.value)
)

const pendingWordIds = computed(() =>
  wordIds.value.filter((id) => practiceResults.value[id] === 'pending')
)

const currentWordId = computed(() => {
  const pending = pendingWordIds.value
  if (pending.length) return pending[queueIndex.value % pending.length]
  return wordIds.value[queueIndex.value % Math.max(wordIds.value.length, 1)]
})

const currentWord = computed(() =>
  words.value.find((w) => String(w.id) === currentWordId.value)
)

const currentQuestion = computed((): QuizQuestion | null => {
  const w = currentWord.value
  if (!w || wordPool.value.length < 4) return null
  return buildPracticeQuestion(w, wordPool.value, practiceMode.value)
})

const progressText = computed(() => {
  const done = wordIds.value.filter(
    (id) => practiceResults.value[id] === 'correct' || practiceResults.value[id] === 'wrong'
  ).length
  return `${done} / ${wordIds.value.length} 词已练习`
})

function syncResultsFromStorage() {
  practiceResults.value = { ...loadPracticeResults() }
}

async function loadData() {
  loading.value = true
  try {
    wordIds.value = getGraphPracticeWordIds()
    if (!wordIds.value.length) {
      router.replace('/words')
      return
    }
    syncResultsFromStorage()
    const practiceSet = new Set(wordIds.value)
    const [wordsRes, vizRes] = await Promise.all([api.listWords(), api.memoryViz()])
    const pool = wordsRes.data
    wordPool.value = pool
    words.value = pool.filter((w) => practiceSet.has(String(w.id)))
    const displayIds = resolvePracticeDisplayIds(
      wordIds.value,
      getGraphPracticeDisplayIds(),
      vizRes.data
    )
    graphNodes.value = buildPracticeGraphNodes(
      displayIds,
      vizRes.data.graph.nodes,
      pool
    )
    graphLinks.value = buildPracticeGraphLinks(displayIds, vizRes.data.graph.links)
    if (pool.length < 4) {
      router.replace('/words')
      return
    }
  } finally {
    loading.value = false
    resetQuestion()
  }
}

function resetQuestion() {
  selected.value = ''
  submittedAnswer.value = ''
  showResult.value = false
  isCorrect.value = false
  startQuestionTimer()
}

function onGraphSelect(id: string) {
  const idx = pendingWordIds.value.indexOf(id)
  if (idx >= 0) queueIndex.value = idx
  else {
    const i = wordIds.value.indexOf(id)
    if (i >= 0) queueIndex.value = i
  }
  resetQuestion()
}

async function submitAnswer(answer: string) {
  const q = currentQuestion.value
  if (!q || showResult.value) return
  submittedAnswer.value = answer

  const result = await submitQuizAnswer('daily', {
    word_id: q.word_id,
    question_type: q.question_type,
    user_answer: answer,
    correct_answer: q.correct_answer,
    duration_seconds: consumeDurationSeconds(),
  })

  const ok =
    result.ok && result.is_correct !== undefined
      ? result.is_correct
      : q.question_type === 'spell'
        ? answer.toLowerCase() === q.correct_answer.toLowerCase()
        : answer === q.correct_answer

  isCorrect.value = ok
  savePracticeResult(String(q.word_id), ok ? 'correct' : 'wrong')
  syncResultsFromStorage()
  showResult.value = true
}

function onSelect(answer: string) {
  selected.value = answer
  return submitAnswer(answer)
}

function nextQuestion() {
  if (sessionComplete.value) return
  const pending = pendingWordIds.value
  if (pending.length > 1) {
    queueIndex.value = (queueIndex.value + 1) % pending.length
  }
  resetQuestion()
}

function switchMode(mode: PracticeMode) {
  practiceMode.value = mode
  resetQuestion()
}

function finishAndBack() {
  router.push({ path: '/words', query: { view: 'memory' } })
}

onMounted(loadData)

watch(practiceMode, () => {
  if (!loading.value) resetQuestion()
})
</script>

<template>
  <div class="practice-page">
    <header class="practice-header">
      <button type="button" class="btn-back" @click="finishAndBack">← 返回记忆曲线</button>
      <h1 class="practice-title">关联练习</h1>
      <span class="practice-progress">{{ progressText }}</span>
    </header>

    <p v-if="loading" class="loading-hint">加载中...</p>

    <template v-else>
      <section class="graph-section card">
        <p class="section-hint">
          {{ sessionComplete ? '已全部完成 · 节点与连线已按对错着色' : '答对变绿 · 答错变红 · 全部完成后连线变色' }}
        </p>
        <WordGraphCanvas
          v-if="graphNodes.length"
          class="practice-graph"
          :nodes="graphNodes"
          :links="graphLinks"
          :practice-results="practiceResults"
          :session-complete="sessionComplete"
          @select="onGraphSelect"
        />
      </section>

      <section class="quiz-section card">
        <div v-if="sessionComplete" class="done-banner">
          <p>本轮练习已完成 🎉</p>
          <button type="button" class="btn btn-primary" @click="finishAndBack">返回记忆曲线</button>
        </div>

        <template v-else>
          <div class="mode-tabs">
            <button
              v-for="m in modes"
              :key="m.key"
              type="button"
              :class="['mode-tab', { active: practiceMode === m.key }]"
              @click="switchMode(m.key)"
            >
              {{ m.label }}
            </button>
          </div>

          <template v-if="currentQuestion && practiceMode !== 'spell'">
            <QuizCard
              :question="currentQuestion"
              :index="queueIndex"
              :total="pendingWordIds.length || wordIds.length"
              :selected="selected"
              :show-result="showResult"
              :is-correct="isCorrect"
              @select="onSelect"
            />
            <button
              v-if="showResult"
              class="btn btn-primary next-btn"
              @click="nextQuestion"
            >
              下一题
            </button>
          </template>

          <template v-else-if="currentQuestion && practiceMode === 'spell'">
            <SpellCard
              ref="spellCardRef"
              :question="currentQuestion"
              :index="queueIndex"
              :total="pendingWordIds.length || wordIds.length"
              :show-result="showResult"
              :is-correct="isCorrect"
              :submitted-answer="submittedAnswer"
              @submit="onSelect"
            />
            <button
              v-if="showResult"
              class="btn btn-primary next-btn"
              @click="nextQuestion"
            >
              下一题
            </button>
          </template>

          <p v-else class="loading-hint">词库不足，无法出题</p>
        </template>
      </section>
    </template>
  </div>
</template>

<style scoped>
.practice-page {
  display: flex;
  flex-direction: column;
  min-height: 100%;
  padding-bottom: 24px;
}
.practice-header {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 12px;
}
.btn-back {
  border: none;
  background: none;
  color: var(--primary);
  font-size: 14px;
  cursor: pointer;
  padding: 0;
}
.practice-title {
  font-size: 18px;
  margin: 0;
  flex: 1;
}
.practice-progress {
  font-size: 13px;
  color: var(--muted);
}
.graph-section {
  flex: 0 0 auto;
  margin-bottom: 12px;
  padding: 12px;
}
.section-hint {
  font-size: 12px;
  color: var(--muted);
  margin: 0 0 8px;
}
.practice-graph :deep(.graph-wrap) {
  min-height: 38vh;
}
.practice-graph :deep(.graph-canvas) {
  min-height: 34vh;
}
.quiz-section {
  flex: 1;
  padding: 12px;
}
.mode-tabs {
  display: flex;
  gap: 6px;
  margin-bottom: 12px;
  flex-wrap: wrap;
}
.mode-tab {
  flex: 1;
  min-width: 90px;
  padding: 8px 6px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: #fff;
  font-size: 12px;
  cursor: pointer;
}
.mode-tab.active {
  border-color: var(--primary);
  background: rgba(79, 110, 247, 0.12);
  color: var(--primary);
  font-weight: 600;
}
.next-btn {
  width: 100%;
  margin-top: 12px;
}
.done-banner {
  text-align: center;
  padding: 24px 12px;
}
.done-banner p {
  margin-bottom: 16px;
  font-size: 16px;
}
.loading-hint {
  text-align: center;
  color: var(--muted);
  padding: 20px;
}
</style>
