<template>
  <div class="layer2-speaking">
    <!-- 创建方式切换 -->
    <CreationModeSwitch v-model="creationMode" />

    <!-- AI 生成模式 -->
    <AIGenerationForm v-if="creationMode === 'ai'" />

    <!-- 手动创建模式 —— 直接进入配置页 -->
    <div v-else-if="creationMode === 'manual'" class="manual-create">
      <div class="manual-hint">
        <p class="manual-text">选择一种口语任务类型开始手动创建</p>
      </div>
      <div class="manual-task-list">
        <button
          v-for="taskType in manualTaskTypes"
          :key="taskType.id"
          class="manual-task-item"
          @click="handleManualCreate(taskType.id)"
        >
          <div class="task-item-icon" v-html="taskType.icon"></div>
          <div class="task-item-info">
            <span class="task-item-name">{{ taskType.name }}</span>
            <span class="task-item-category">{{ taskType.category }}</span>
          </div>
          <svg class="task-item-arrow" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
            <path d="M9 18l6-6-6-6" />
          </svg>
        </button>
      </div>
    </div>

    <!-- 智能推荐模式 -->
    <template v-else>
      <!-- 任务类型筛选 -->
      <div class="filter-bar">
        <div class="filter-left">
          <span class="filter-label">任务类型</span>
          <div class="filter-select-wrap">
            <select v-model="selectedTaskType" class="filter-select">
              <option v-for="opt in taskTypeOptions" :key="opt.id" :value="opt.id">
                {{ opt.name }}
              </option>
            </select>
            <svg class="select-arrow" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
              <path d="M6 9l6 6 6-6" />
            </svg>
          </div>
        </div>
      </div>

      <!-- 推荐卡片列表 -->
      <div v-if="filteredTasks.length > 0" class="card-grid">
        <RecommendCard
          v-for="task in filteredTasks"
          :key="task.id"
          :task="task"
          @select="handleSelectTask(task)"
        />
      </div>

      <!-- 空状态 -->
      <div v-else class="empty-state">
        <svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
          <path d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2" />
          <rect x="9" y="3" width="6" height="4" rx="1" />
          <line x1="9" y1="12" x2="15" y2="12" />
          <line x1="9" y1="16" x2="13" y2="16" />
        </svg>
        <p class="empty-text">{{ lang.ssNoRecommendations }}</p>
      </div>
    </template>
  </div>
</template>

<script lang="ts" setup>
import { ref, computed, inject } from 'vue'
import { lang } from '@/main'
import type { CreationMode, SpeakingRecommendationTask, TopicDiscussionTask } from '@/types/englishSpeaking'
import type { ArticleReadingTask } from '@/types/articleReading'
import { ARTICLE_READING_TOOL_TYPE, TOPIC_DISCUSSION_TOOL_TYPE } from '@/configs/englishSpeakingTools'
import { injectKeySingleSlideMode } from '@/types/injectKey'
import { filterSpeakingTasks, type SpeakingTaskFilter } from '../preview/articleReadingModel'
import { useSpeakingStore } from '@/store/speaking'
import { useArticleReadingStore } from '@/store/articleReading'
import useCreateElement from '@/hooks/useCreateElement'
import useSlideHandler from '@/hooks/useSlideHandler'
import { createSpeakingConfig } from '@/services/speaking'
import { createArticleConfig } from '../services/articleReading'
import { friendlyArticleError } from '../services/articleErrors'
import message from '@/utils/message'
import topicTasksData from '../data/topicDiscussionTasks.json'
import articleTasksData from '../data/articleReadingTasks.json'
import CreationModeSwitch from '../components/CreationModeSwitch.vue'
import RecommendCard from '../components/RecommendCard.vue'
import AIGenerationForm from '../components/AIGenerationForm.vue'

const props = defineProps<{
  unitId: string
}>()

const emit = defineEmits<{
  (e: 'openConfig'): void
}>()

const speakingStore = useSpeakingStore()
const articleStore = useArticleReadingStore()

const creationMode = ref<CreationMode>('smart')
const selectedTaskType = ref<SpeakingTaskFilter>('all')

// 任务类型筛选选项
const taskTypeOptions = [
  { id: 'all', name: lang.ssAll as string },
  { id: 'topic-discussion', name: lang.ssTopicDiscussion as string },
  { id: 'article-reading', name: lang.ssArticleReading as string },
]

// 手动创建的任务类型列表
const manualTaskTypes = [
  {
    id: 'topic-discussion',
    name: lang.ssTopicDiscussion as string,
    category: lang.ssFreeDialogue as string,
    icon: '<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z"/></svg>',
  },
  {
    id: 'article-reading',
    name: lang.ssArticleReading as string,
    category: lang.ssArticleReadAloud as string,
    icon: '<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 19.5A2.5 2.5 0 016.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 014 19.5v-15A2.5 2.5 0 016.5 2z"/></svg>',
  },
]

// 根据 unitId 获取推荐任务（话题讨论 + 文章朗读，靠 taskType 判别，不互相伪装）
const unitTasks = computed<SpeakingRecommendationTask[]>(() => {
  const topics = topicTasksData as Record<string, TopicDiscussionTask[]>
  const articles = articleTasksData as Record<string, ArticleReadingTask[]>
  return [...(topics[props.unitId] || []), ...(articles[props.unitId] || [])]
})

// 按任务类型筛选
const filteredTasks = computed(() => filterSpeakingTasks(unitTasks.value, selectedTaskType.value))

// 新交互：点卡片即新建一页 + 创建配置 + 插入画布元素；配置页改由"点击画布里的 77 型元素"唤起
const { createFrameElement } = useCreateElement()
const { createSlide, replaceAllSlidesWithNew } = useSlideHandler()
const inserting = ref(false)

// 由 indexEn.vue provide；其余编辑器没有 provide，这里拿到 default false
const singleSlideMode = inject(injectKeySingleSlideMode, false)

// 腾出一页空白页来放新工具。
//
// 单页模式（英语展示页）下换成「替换掉全部页面」：那个编辑器藏了缩略图、只允许一页，
// 再往后加页的话老师看不见也切不过去。两条路都保证新页是空的，因为 createFrameElement
// 会拒绝插进已经有 frame 的页面。
//
// 已知问题（两种模式都有，单页模式下更频繁）：被替换掉的那个工具，它的 config 已经
// POST 到后端了，这里只是丢掉画布上引用它的 frame 元素，后端那条记录会变成孤儿。
// 服务端目前没有删除 config 的接口，前端无法回收。
const openSlideForNewTool = () => {
  if (singleSlideMode) replaceAllSlidesWithNew()
  else createSlide()
}

async function insertSpeakingToolToCanvas(source: 'select' | 'manual') {
  if (inserting.value) return
  inserting.value = true
  try {
    const { id } = await createSpeakingConfig(speakingStore.config)
    openSlideForNewTool()
    createFrameElement(id, TOPIC_DISCUSSION_TOOL_TYPE)
    // 创建后立即唤起左侧配置面板（与点击画布 77 型 frame 同款信号），使用户可直接编辑
    speakingStore.openConfigPanel()
    message.success(source === 'select' ? '已添加口语练习到幻灯片' : '已添加空白口语工具，点击画布上的元素进行配置')
  } catch (err: any) {
    console.error('[speaking] create failed:', err)
    message.error(err?.message || '创建口语工具失败')
  } finally {
    inserting.value = false
  }
}

// 文章朗读走同一把 inserting 门闩：POST 成功后才建页与元素，失败不留孤立页面。
// 用文章自己的建立接口而不是共用的 createSpeakingConfig：后端在那里同步把整篇示范
// 音频合成好，全部成功才写入。所以「选推荐卡片」这条路（正文一出生就是满的）建完
// 就已经烤热，学生点示范时是 S3 直接命中。这一步因此可能要几秒 —— inserting 门闩
// 本来就在挡重复点击，按钮的 loading 态也照旧生效。
async function insertArticleToolToCanvas(source: 'select' | 'manual') {
  if (inserting.value) return
  inserting.value = true
  // 选推荐卡片这条路正文一出生就是满的，后端会当场把整篇示范音频合成好 —— 几秒。
  // 这里的卡片点下去没有任何自身的 loading 态，不挂一条常驻提示，老师看到的就是
  // 「点了没反应」，然后再点一次（inserting 门闩会吃掉，但他不知道）。
  // 手动创建那条路正文是空的，后端立刻返回，提示一闪而过，无妨。
  const pending = message.info(lang.ssArticleGeneratingDemo as string, { duration: 0 })
  try {
    const { id } = await createArticleConfig(articleStore.config)
    openSlideForNewTool()
    createFrameElement(id, ARTICLE_READING_TOOL_TYPE)
    articleStore.openConfigPanel(id)
    message.success(source === 'select' ? lang.ssArticleTemplateCreated : lang.ssArticleManualCreated)
  } catch (err: unknown) {
    console.error('[article-reading] create failed:', err)
    // 经 friendlyArticleError：合成失败时后端给的是 `Demo audio synthesis failed: [2]`，
    // 原样甩出去老师看不懂，也不会知道配置根本没保存
    message.error(friendlyArticleError(err))
  } finally {
    pending.close()
    inserting.value = false
  }
}

// 选择推荐卡片 → 预填充 store → 立即创建配置 + 插入元素
const handleSelectTask = (task: SpeakingRecommendationTask) => {
  if (task.taskType === 'article-reading') {
    articleStore.prefillFromTask(task, speakingStore.config.grade)
    void insertArticleToolToCanvas('select')
    return
  }
  speakingStore.prefillFromTask(task.titleEn, task.vocabulary, task.sentences)
  void insertSpeakingToolToCanvas('select')
}

// 手动创建 → 清空 store → 立即创建配置 + 插入元素
const handleManualCreate = (taskTypeId: string) => {
  if (taskTypeId === 'article-reading') {
    articleStore.resetConfigEmpty(speakingStore.config.grade)
    void insertArticleToolToCanvas('manual')
    return
  }
  speakingStore.resetConfigEmpty()
  void insertSpeakingToolToCanvas('manual')
}
</script>

<style lang="scss" scoped>
.layer2-speaking {
  padding: 16px 20px;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

// 筛选栏
.filter-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.filter-left {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 1;
}

.filter-label {
  font-size: 12px;
  font-weight: 500;
  color: #6b7280;
  white-space: nowrap;
}

.filter-select-wrap {
  position: relative;
  flex: 1;
}

.filter-select {
  width: 100%;
  appearance: none;
  padding: 6px 28px 6px 12px;
  border: 1px solid rgba(0, 0, 0, 0.08);
  border-radius: 12px;
  background: #f9fafb;
  font-size: 13px;
  color: #374151;
  cursor: pointer;
  transition: all 0.2s;

  &:focus {
    outline: none;
    border-color: #f97316;
    background: #fff;
    box-shadow: 0 0 0 2px rgba(249, 115, 22, 0.1);
  }
}

.select-arrow {
  position: absolute;
  right: 10px;
  top: 50%;
  transform: translateY(-50%);
  color: #9ca3af;
  pointer-events: none;
}

// 推荐卡片网格
.card-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}

// 空状态
.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 32px 16px;
  color: #d1d5db;
}

.empty-text {
  font-size: 13px;
  color: #9ca3af;
  margin: 0;
}

// 手动创建
.manual-create {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.manual-hint {
  padding: 0;
}

.manual-text {
  font-size: 13px;
  color: #6b7280;
  margin: 0;
}

.manual-task-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.manual-task-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 14px;
  background: #fff;
  border: 1px solid rgba(0, 0, 0, 0.06);
  border-radius: 14px;
  cursor: pointer;
  transition: all 0.2s;
  text-align: left;

  &:hover {
    border-color: rgba(0, 0, 0, 0.12);
    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);

    .task-item-arrow {
      color: #f97316;
    }
  }
}

.task-item-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: 10px;
  background: linear-gradient(135deg, #fff7ed, #fff);
  border: 1px solid rgba(249, 115, 22, 0.15);
  color: #f97316;
  flex-shrink: 0;
}

.task-item-info {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.task-item-name {
  font-size: 13px;
  font-weight: 500;
  color: #111827;
}

.task-item-category {
  font-size: 11px;
  color: #9ca3af;
}

.task-item-arrow {
  color: #d1d5db;
  flex-shrink: 0;
  transition: color 0.2s;
}
</style>
