<template>
  <div class="topic-discussion-preview">
    <!-- Ready 阶段：极简首页（参照 enspeak 布局） -->
    <div v-if="dialogueState === 'checking-history'" class="ready-stage">
      <div class="ready-header">
        <h1 class="ready-title">
          <span class="ready-title-icon">💬</span>
          Topic Discussion
        </h1>
        <p class="ready-subtitle">正在读取你的练习记录...</p>
      </div>
      <div class="ready-body">
        <span class="start-btn-spinner" />
      </div>
    </div>

    <div v-else-if="dialogueState === 'ready'" class="ready-stage">
      <div class="ready-header">
        <h1 class="ready-title">
          <span class="ready-title-icon">💬</span>
          Topic Discussion
        </h1>
        <p class="ready-subtitle">话题讨论 · 与 AI 伙伴练习英语对话</p>
      </div>

      <div class="ready-body">
        <span class="topic-emoji">🐼</span>
        <h3 class="topic-name">{{ speakingStore.config.topic || topic }}</h3>
      </div>

      <div class="ready-footer">
        <button class="start-btn" :disabled="sessionCreating" @click="startDialogue">
          <svg v-if="!sessionCreating" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor"
            stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
            <path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z" />
            <path d="M19 10v2a7 7 0 0 1-14 0v-2" />
            <line x1="12" y1="19" x2="12" y2="23" />
            <line x1="8" y1="23" x2="16" y2="23" />
          </svg>
          <span v-else class="start-btn-spinner" />
          {{ sessionCreating ? '创建中…' : '开始对话' }}
        </button>
        <p v-if="sessionError" class="session-error-text">{{ sessionError }}</p>
      </div>
    </div>

    <!-- Chatting 阶段：直接渲染 DialogueChatView -->
    <DialogueChatView
      v-else-if="dialogueState === 'chatting'"
      :topic="speakingStore.config.topic || topic"
      :keywords="speakingStore.config.learningGoals.vocabulary.length ? speakingStore.config.learningGoals.vocabulary : keywords"
      :ai-name="mockRole.name"
      :ai-avatar="mockRole.avatar"
      :total-rounds="speakingStore.config.practice.rounds || totalRounds"
      :session-info="preparedSession"
      @complete="handleDialogueComplete"
      @restart="resetPreview"
    />

    <!-- Completed 阶段：直接渲染报告 -->
    <div v-else class="report-stage">
      <div class="report-scroll">
        <div v-if="reportError" class="report-error">
          {{ reportError }}
        </div>
        <OverallReport
          v-if="overallEvaluationForDisplay"
          :evaluation="overallEvaluationForDisplay"
          :role="mockRole"
          :scoreDisplayMode="'numeric'"
          @restart="resetPreview"
          @complete="resetPreview"
        />
        <div v-if="shouldShowOverallReport" class="report-divider" />
        <DetailedReport :sentenceEvaluations="displaySentenceEvaluations" />
      </div>
    </div>

  </div>
</template>

<script lang="ts" setup>
import { ref, computed, watch, onMounted, onUnmounted } from 'vue'
import type { DialogueReport, OverallEvaluation, PreviewAIRole, PreviewDialogueState, SessionStartInfo } from '@/types/englishSpeaking'
import { useSpeakingStore } from '@/store/speaking'
import { getSpeakingConfig } from '@/services/speaking'
import { createDialogueApi, DialogueApiError } from '../services/llmService'

import DialogueChatView from './DialogueChatView.vue'
import OverallReport from './OverallReport.vue'
import DetailedReport from './DetailedReport.vue'

interface Props {
  topic?: string
  keywords?: string[]
  totalRounds?: number
  /** 配置 id（由 FrameElement 从 elementInfo.url 传入） */
  configId?: string
}

const props = withDefaults(defineProps<Props>(), {
  topic: '我最喜欢的动物',
  keywords: () => ['favorite', 'adorable', 'bamboo', 'habitat', 'wildlife', 'endangered'],
  totalRounds: 3,
  configId: '',
})

const dialogueState = ref<PreviewDialogueState>('ready')
const sessionCreating = ref(false)
const sessionError = ref<string | null>(null)
const preparedSession = ref<SessionStartInfo | null>(null)
const historyChecked = ref(false)
const historyLoadToken = ref(0)

const runtimeParams = computed(() => {
  const params = new URLSearchParams(window.location.search)
  return {
    mode: params.get('mode'),
    userId: params.get('userid'),
  }
})

const isStudentRuntime = computed(() => runtimeParams.value.mode === 'student')
const runtimeUserId = computed(() => runtimeParams.value.userId || '')

const mockRole: PreviewAIRole = {
  id: 'tom',
  name: 'Tom',
  avatar: '😊',
  identity: 'Friendly Teacher',
  personality: 'Patient and encouraging',
  speakingStyle: 'casual',
  speed: 'normal',
  isCustom: false,
  isRecommended: true,
}

const mockEvaluation: OverallEvaluation = {
  overallScore: 85,
  scoreLevel: 'good',
  percentile: 78,
  dimensions: {
    fluency: 82,
    interaction: 88,
    vocabulary: 76,
    grammar: 90,
  },
  aiComment: 'Great job! You showed good understanding of the topic. Your pronunciation was clear and your responses were relevant. Keep practicing to improve your fluency and try using more advanced vocabulary!',
  highlights: [
    'Clear pronunciation of key words',
    'Good use of complete sentences',
    'Natural conversation flow',
  ],
  improvements: [
    'Try using more descriptive adjectives',
    'Practice linking words for smoother speech',
    'Expand vocabulary range for the topic',
  ],
  nextChallenge: {
    difficulty: 'Medium',
    unlockedTopic: 'My Dream Job',
    suggestedMode: 'Free Talk',
  },
  statistics: {
    totalRounds: 3,
    averageScore: 83,
    highestScore: 92,
    highestRound: 2,
    grammarErrors: 2,
    excellentExpressions: 4,
    totalDuration: 180,
  },
  sentenceEvaluations: [
    {
      id: 'se-1', round: 1, role: 'ai',
      content: "Hi! What's your favorite animal?",
      audioDuration: 3,
    },
    {
      id: 'se-2', round: 1, role: 'student',
      content: 'I like pandas. They are very cute!',
      audioDuration: 4, score: 88,
      pronunciation: { accuracy: 90, intonation: 85, stress: 82, fluency: 88 },
      feedback: {
        comment: 'Good pronunciation of "pandas" with natural intonation.',
        betterExpression: 'I really love pandas because they are incredibly cute!',
      },
    },
    {
      id: 'se-3', round: 2, role: 'ai',
      content: 'Pandas are adorable! Have you seen them at the zoo?',
      audioDuration: 4,
    },
    {
      id: 'se-4', round: 2, role: 'student',
      content: 'Yes, I went to the zoo last month.',
      audioDuration: 3, score: 92,
      pronunciation: { accuracy: 95, intonation: 90, stress: 88, fluency: 92 },
      feedback: {
        comment: 'Excellent fluency and clear past tense usage.',
        betterExpression: 'I visited the Beijing Zoo last month and saw giant pandas there.',
      },
    },
    {
      id: 'se-5', round: 3, role: 'ai',
      content: "That's great! What do pandas like to eat?",
      audioDuration: 3,
    },
    {
      id: 'se-6', round: 3, role: 'student',
      content: 'They like to eat bamboo.',
      audioDuration: 3, score: 78,
      pronunciation: { accuracy: 80, intonation: 75, stress: 76, fluency: 82 },
      feedback: {
        comment: 'Correct answer. Try using a more natural phrase for animal diets.',
        betterExpression: 'Pandas mainly feed on bamboo, but they also eat fruits and vegetables.',
      },
    },
  ],
}

const realEvaluation = ref<OverallEvaluation | null>(null)
const reportStatus = ref<DialogueReport['status'] | null>(null)
const reportError = ref('')
const reportFetchFailed = ref(false)

const displayEvaluation = computed<OverallEvaluation | null>(() => {
  const real = realEvaluation.value
  if (real) return real
  if (reportFetchFailed.value) return null
  return mockEvaluation
})

const shouldShowOverallReport = computed(() => {
  return !!displayEvaluation.value
    && !reportError.value
    && reportStatus.value !== 'failed'
    && reportStatus.value !== 'incomplete'
})

const overallEvaluationForDisplay = computed(() => shouldShowOverallReport.value ? displayEvaluation.value : null)
const displaySentenceEvaluations = computed(() => displayEvaluation.value?.sentenceEvaluations ?? [])

function isHistoryTokenCurrent(token: number) {
  return token === historyLoadToken.value
}

function nextHistoryLoadToken() {
  historyLoadToken.value += 1
  return historyLoadToken.value
}

async function startDialogue() {
  if (sessionCreating.value) return
  if (isStudentRuntime.value) {
    if (!props.configId) {
      sessionError.value = '口语工具配置缺失，请联系老师重新发布。'
      return
    }
    if (!runtimeUserId.value) {
      sessionError.value = '学生身份缺失，请从课程入口重新进入。'
      return
    }
  }
  sessionCreating.value = true
  sessionError.value = null
  reportFetchFailed.value = false
  try {
    const api = createDialogueApi()
    const info = await api.createSession({
      topic: speakingStore.config.topic || props.topic,
      grade: speakingStore.config.grade,
      totalRounds: speakingStore.config.practice.rounds ?? props.totalRounds,
      durationMinutes: speakingStore.config.practice.duration,
      roleId: mockRole.id,
      vocabulary: speakingStore.config.learningGoals.vocabulary,
      sentences: speakingStore.config.learningGoals.sentences,
      configId: props.configId || null,
      userId: isStudentRuntime.value ? runtimeUserId.value : null,
    })
    preparedSession.value = {
      sessionId: info.sessionId,
      expiresAt: info.expiresAt,
      currentRound: info.currentRound,
    }
    dialogueState.value = 'chatting'
  } catch (err: unknown) {
    if (err instanceof DialogueApiError) {
      sessionError.value = `创建会话失败(${err.status}),请重试`
    } else {
      sessionError.value = '创建会话失败,请重试'
    }
  } finally {
    sessionCreating.value = false
  }
}

async function waitForCompletedHistoryReport(
  api: ReturnType<typeof createDialogueApi>,
  sessionId: string,
  token: number,
): Promise<DialogueReport | null> {
  const maxAttempts = 30
  const intervalMs = 2000

  try {
    for (let attempt = 1; attempt <= maxAttempts; attempt++) {
      if (!isHistoryTokenCurrent(token)) return null
      const report = await api.getReport(sessionId)
      if (!isHistoryTokenCurrent(token)) return null
      if (report.status === 'ready' || report.status === 'failed' || report.status === 'incomplete') {
        return report
      }
      await new Promise(resolve => setTimeout(resolve, intervalMs))
      if (!isHistoryTokenCurrent(token)) return null
    }
  } catch (err) {
    console.error('[speaking] load completed history report failed:', err)
    return null
  }

  return null
}

async function loadLatestStudentSession(token = nextHistoryLoadToken()) {
  if (historyChecked.value) return
  historyChecked.value = true
  if (!isStudentRuntime.value) return

  if (!props.configId) {
    if (!isHistoryTokenCurrent(token)) return
    sessionError.value = '口语工具配置缺失，请联系老师重新发布。'
    return
  }
  if (!runtimeUserId.value) {
    if (!isHistoryTokenCurrent(token)) return
    sessionError.value = '学生身份缺失，请从课程入口重新进入。'
    return
  }

  if (!isHistoryTokenCurrent(token)) return
  dialogueState.value = 'checking-history'
  sessionError.value = null
  try {
    const api = createDialogueApi()
    const { session } = await api.getLatestSession(props.configId, runtimeUserId.value)
    if (!isHistoryTokenCurrent(token)) return
    if (!session) {
      preparedSession.value = null
      dialogueState.value = 'ready'
      return
    }

    preparedSession.value = {
      sessionId: session.sessionId,
      expiresAt: session.expiresAt,
      currentRound: session.currentRound,
      messages: session.messages,
    }

    if (session.status === 'completed') {
      const report = await waitForCompletedHistoryReport(api, session.sessionId, token)
      if (!isHistoryTokenCurrent(token)) return
      handleDialogueComplete(report)
      return
    }

    if (session.status !== 'active') {
      preparedSession.value = null
      sessionError.value = '上次练习已失效，请重新开始。'
      dialogueState.value = 'ready'
      return
    }

    dialogueState.value = 'chatting'
  } catch (err: unknown) {
    if (!isHistoryTokenCurrent(token)) return
    console.error('[speaking] load latest session failed:', err)
    dialogueState.value = 'ready'
    if (err instanceof DialogueApiError) {
      sessionError.value = `读取历史会话失败(${err.status})，请刷新重试`
    } else {
      sessionError.value = '读取历史会话失败，请刷新重试'
    }
  }
}

function handleDialogueComplete(report: DialogueReport | null) {
  reportFetchFailed.value = !report
  reportStatus.value = report?.status ?? null
  realEvaluation.value = report?.evaluation ?? null
  if (!report) reportError.value = '报告生成超时或获取失败，请稍后重试。'
  else if (report.status === 'failed') reportError.value = '报告生成失败，部分语音评分未完成。'
  else if (report?.status === 'incomplete') reportError.value = '本次练习没有足够的有效回答生成报告。'
  else reportError.value = ''
  dialogueState.value = 'completed'
}

function resetPreview() {
  nextHistoryLoadToken()
  dialogueState.value = 'ready'
  realEvaluation.value = null
  reportStatus.value = null
  reportError.value = ''
  reportFetchFailed.value = false
  preparedSession.value = null
  sessionError.value = null
  sessionCreating.value = false
}

// ── Sync with speakingStore (让 CanvasTool 可以驱动"重置预览") ──
const speakingStore = useSpeakingStore()

watch(dialogueState, (s) => { speakingStore.setPreviewState(s) }, { immediate: true })

watch(
  () => speakingStore.resetSignal,
  (val, old) => {
    if (val !== old) resetPreview()
  },
)

// ── 根据 configId 从后端拉回配置注入 store ──
async function loadConfigFromBackend(id: string) {
  const token = nextHistoryLoadToken()
  if (!id) {
    await loadLatestStudentSession(token)
    return
  }
  try {
    const { config } = await getSpeakingConfig(id)
    if (!isHistoryTokenCurrent(token)) return
    speakingStore.$patch({ config })
  } catch (err) {
    if (!isHistoryTokenCurrent(token)) return
    console.error('[speaking] load config failed:', err)
  } finally {
    if (isHistoryTokenCurrent(token)) {
      await loadLatestStudentSession(token)
    }
  }
}

watch(() => props.configId, (id) => {
  historyChecked.value = false
  loadConfigFromBackend(id)
})

onMounted(() => {
  speakingStore.setPreviewState(dialogueState.value)
  loadConfigFromBackend(props.configId)
})
onUnmounted(() => {
  nextHistoryLoadToken()
  speakingStore.setPreviewState('ready')
})
</script>

<style lang="scss" scoped>
.topic-discussion-preview {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  background: #fff;
  position: relative;
  overflow: hidden;

  // flex 嵌套 overflow 生效的前提：flex 子默认 min-height: auto 会被内容撑大，
  // 让 ready-stage / report-stage / DialogueChatView 根节点能 shrink 到父高度
  > * {
    min-height: 0;
  }
}

// ─── Ready 阶段 ───
.ready-stage {
  flex: 1;
  display: flex;
  flex-direction: column;
  background: #fff;
}
.ready-header {
  padding: 20px 24px 12px;
  text-align: center;
  border-bottom: 1px solid #f9fafb;
}
.ready-title {
  font-size: 20px;
  font-weight: 600;
  color: #111827;
  margin: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
}
.ready-title-icon { font-size: 22px; }
.ready-subtitle {
  font-size: 13px;
  color: #9ca3af;
  margin: 4px 0 0;
}
.ready-body {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 16px;
  padding: 24px;
}
.topic-emoji { font-size: 56px; line-height: 1; }
.topic-name {
  font-size: 18px;
  font-weight: 600;
  color: #1f2937;
  margin: 0;
}
.ready-footer {
  padding: 16px 24px 20px;
  border-top: 1px solid #f9fafb;
  background: #fafbfc;
  display: flex;
  flex-direction: column;
  align-items: center;
}
.start-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 9px 28px;
  border-radius: 999px;
  background: #f97316;
  color: #fff;
  border: none;
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
  box-shadow: 0 4px 12px rgba(249, 115, 22, 0.25);
  transition: background 0.2s, transform 0.15s;
  &:hover { background: #ea580c; }
  &:active { transform: scale(0.97); }
}
.start-btn:disabled {
  opacity: 0.6;
  cursor: wait;
  background: #fb923c;
}
.start-btn-spinner {
  width: 14px;
  height: 14px;
  border: 2px solid rgba(255, 255, 255, 0.4);
  border-top-color: #fff;
  border-radius: 50%;
  animation: start-btn-spin 0.8s linear infinite;
  display: inline-block;
}
@keyframes start-btn-spin {
  to { transform: rotate(360deg); }
}
.session-error-text {
  margin: 8px 0 0;
  font-size: 12px;
  color: #dc2626;
  text-align: center;
}

// ─── Completed 阶段 ───
.report-stage {
  flex: 1;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: #fff;
}
.report-scroll {
  flex: 1;
  overflow-y: auto;
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 24px;
}
.report-divider {
  height: 1px;
  background: #e5e7eb;
  margin: 0;
}
.report-error {
  max-width: 448px;
  margin: 0 auto 12px;
  padding: 10px 12px;
  border: 1px solid #fed7aa;
  border-radius: 8px;
  background: #fff7ed;
  color: #c2410c;
  font-size: 12px;
  line-height: 1.5;
}

</style>
