<template>
  <div class="zj-home" :class="{ 'task-mode': activeMode !== 'courseware' }">
    <section v-if="activeMode === 'courseware'" class="courseware-shell">
      <div class="top-composer">
        <div class="composer-title">
          <span class="mascot">☻</span>
          <h1>智教助手，一句话生成专业级互动课件</h1>
        </div>

        <div class="prompt-card">
          <textarea v-model="prompt" :placeholder="activeConfig.placeholder"></textarea>
          <div v-if="uploadedMaterials.length" class="materials-row">
            <span v-for="item in uploadedMaterials" :key="item.id">
              <el-icon><component :is="item.icon" /></el-icon>
              {{ item.name }}
              <button type="button" @click="removeMaterial(item.id)">×</button>
            </span>
          </div>
          <div class="prompt-toolbar">
            <div class="toolbar-left">
              <button type="button" title="上传文件" @click="pickFile('file')"><el-icon><Paperclip /></el-icon></button>
              <button type="button" title="上传图片" @click="pickFile('image')"><el-icon><Picture /></el-icon></button>
              <input ref="fileInputRef" type="file" class="hidden-input" :accept="uploadAccept" @change="handleFileChange" />
              <MaterialPicker v-model="uploadedMaterials" :show-selected="false" />
              <button
                v-for="chip in creatorChips"
                :key="chip.mode"
                type="button"
                class="chip-btn"
                :class="{ active: chip.mode === activeMode }"
                @click="setMode(chip.mode)"
              >
                <el-icon><component :is="chip.icon" /></el-icon>
                {{ chip.label }}
              </button>
            </div>
            <div class="toolbar-right">
              <button type="button" class="voice-btn" title="语音输入" :class="{ active: listening }" @click="toggleVoice"><el-icon><Microphone /></el-icon></button>
              <button type="button" class="send-btn" title="开始生成" @click="startCreate"><el-icon><Top /></el-icon></button>
            </div>
          </div>
        </div>
      </div>

      <section class="resource-toolbar">
        <nav class="category-tabs">
          <button
            v-for="cat in categories"
            :key="cat"
            type="button"
            :class="{ active: activeCategory === cat }"
            @click="activeCategory = cat"
          >
            {{ cat }}
            <span v-if="cat === '数学'" class="hot-mini">Hot</span>
          </button>
        </nav>
        <form class="search-pill" @submit.prevent="goResourceSearch">
          <el-icon><Search /></el-icon>
          <input v-model="keyword" placeholder="快速搜索资源" />
        </form>
      </section>

      <section class="resource-grid">
        <article v-for="item in filteredResources" :key="item.id" class="resource-card" @click="openResource(item)">
          <div class="cover" :class="item.coverClass">
            <span v-if="item.hot" class="hot-badge">🔥热门</span>
            <span v-if="item.featured" class="hot-badge featured">精选</span>
            <span class="views"><el-icon><View /></el-icon>{{ item.views }}</span>
            <div class="cover-content">
              <small>{{ item.kicker }}</small>
              <strong>{{ item.coverTitle }}</strong>
              <em>{{ item.coverSub }}</em>
            </div>
            <div v-if="item.visual === 'slides'" class="mini-slides"><span></span><span></span><span></span></div>
            <div v-if="item.visual === 'chart'" class="chart-art"><span></span><span></span><span></span></div>
            <div v-if="item.visual === 'tower'" class="tower-art"></div>
            <div v-if="item.visual === 'people'" class="people-art"><span></span><span></span></div>
            <div v-if="item.visual === 'shape'" class="shape-art"><span></span><span></span><span></span></div>
            <div v-if="item.visual === 'grid'" class="grid-art"><span></span><span></span><span></span><span></span></div>
            <div v-if="item.visual === 'cave'" class="cave-art"></div>
            <div v-if="item.visual === 'festival'" class="festival-art"></div>
          </div>
          <div class="card-body">
            <h3>{{ item.title }}</h3>
            <div class="author-row">
              <span class="avatar-dot" :style="{ background: item.avatar }"></span>
              <span>{{ item.author }}</span>
              <span class="star"><el-icon><Star /></el-icon>{{ item.likes }}</span>
            </div>
          </div>
        </article>
      </section>

      <form class="floating-composer" @submit.prevent="startCreate">
        <span>{{ activeConfig.shortLabel }}｜</span>
        <input v-model="prompt" :placeholder="activeConfig.floatPlaceholder" />
        <button type="button" class="voice-btn" title="语音输入" @click="toggleVoice"><el-icon><Microphone /></el-icon></button>
        <button type="submit" class="send-btn" title="开始生成"><el-icon><Top /></el-icon></button>
      </form>
    </section>

    <section v-else class="task-shell">
      <div class="task-center">
        <div class="task-heading">
          <span class="mascot large">☻</span>
          <h1>Hi, 我是智教助手</h1>
        </div>

        <div class="task-workbench">
          <aside class="tip-card" :class="activeMode">
            <div class="tip-title">
              <strong>{{ activeConfig.label }}</strong>
              <span>小提示</span>
            </div>
            <p>{{ activeConfig.tip }}</p>
            <div class="tip-preview">
              <div class="mini-tabs">
                <span
                  v-for="item in previewTabs"
                  :key="item.mode"
                  :class="{ active: activeMode === item.mode }"
                >{{ item.label }}</span>
              </div>
              <div class="doc-chip" v-if="activeMode === 'exam'">
                <strong>ChinaDaily.doc</strong>
                <small>File · 54KB</small>
              </div>
              <p>{{ activeConfig.previewText }}</p>
            </div>
            <div class="tip-actions">
              <button type="button" @click="prompt = ''">好的</button>
              <button type="button" @click="applyPromptTemplate(activeConfig.examples[0])">试一试</button>
            </div>
          </aside>

          <div class="task-main">
            <div class="task-tabs">
              <button
                v-for="item in taskTabs"
                :key="item.mode"
                type="button"
                :class="{ active: activeMode === item.mode }"
                @click="setMode(item.mode)"
              >
                <el-icon><component :is="item.icon" /></el-icon>
                {{ item.label }}
              </button>
            </div>
            <div class="task-input-card">
              <textarea v-model="prompt" :placeholder="activeConfig.inputPlaceholder"></textarea>
              <div v-if="uploadedMaterials.length" class="materials-row task-materials-row">
                <span v-for="item in uploadedMaterials" :key="item.id">
                  <el-icon><component :is="item.icon" /></el-icon>
                  {{ item.name }}
                  <button type="button" @click="removeMaterial(item.id)">×</button>
                </span>
              </div>
              <div class="task-toolbar">
                <div>
                  <button type="button" title="上传文件" @click="pickFile('file')"><el-icon><Paperclip /></el-icon></button>
                  <button type="button" title="上传图片" @click="pickFile('image')"><el-icon><Picture /></el-icon></button>
                  <MaterialPicker v-model="uploadedMaterials" :show-selected="false" />
                </div>
                <div>
                  <button type="button" class="voice-btn" title="语音输入" :class="{ active: listening }" @click="toggleVoice"><el-icon><Microphone /></el-icon></button>
                  <button type="button" class="send-btn muted" title="开始生成" @click="startCreate"><el-icon><Top /></el-icon></button>
                </div>
              </div>
            </div>

            <section class="hot-prompts">
              <h2>大家都在用</h2>
              <button v-for="item in activeConfig.examples" :key="item.prompt" type="button" @click="applyPromptTemplate(item)">
                <el-icon><component :is="activeConfig.icon" /></el-icon>
                <span>{{ item.prompt }}</span>
                <em v-if="item.hot">热门</em>
                <small>{{ item.heat }} 热度</small>
              </button>
            </section>
          </div>
        </div>
      </div>

      <section class="case-section">
        <div class="case-tabs">
          <button
            v-for="tab in caseTabs"
            :key="tab.mode"
            type="button"
            :class="{ active: caseFilter === tab.mode }"
            @click="caseFilter = tab.mode"
          >
            {{ tab.label }}
          </button>
        </div>
        <div class="case-grid">
          <article v-for="item in filteredCases" :key="item.title" class="case-card">
            <div class="case-cover" :class="item.theme">
              <span>{{ item.type }}</span>
              <div></div>
            </div>
            <h3>{{ item.title }}</h3>
            <p><el-icon><Document /></el-icon>{{ item.file }}</p>
          </article>
        </div>
      </section>
    </section>
  </div>
</template>

<script setup lang="ts">
import { computed, ref, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import { parseMaterial } from '@/api/ai'
import MaterialPicker from '@/components/common/MaterialPicker.vue'
import { useUserStore } from '@/stores/user'
import { buildMaterialPromptBlock, fileParseToContext, formatMaterialFileSize, type MaterialContextItem } from '@/utils/materialContext'
import { createSpeechController } from '@/utils/speech'

type Mode = 'courseware' | 'exam' | 'exercise' | 'lesson' | 'animation' | 'analytics'

const route = useRoute()
const router = useRouter()
const userStore = useUserStore()
const prompt = ref('')
const keyword = ref('')
const activeCategory = ref('推荐')
const caseFilter = ref('all')
const fileInputRef = ref<HTMLInputElement>()
const uploadAccept = ref('.txt,.md,.csv,.json,.docx,.pptx,.pdf,.xlsx,image/*')
const listening = ref(false)
const uploadedMaterials = ref<MaterialContextItem[]>([])
const speech = createSpeechController({
  onStart: () => { listening.value = true },
  onText: (text) => { prompt.value = `${prompt.value} ${text}`.trim() },
  onError: () => {
    listening.value = false
    ElMessage.warning('语音识别失败，请检查浏览器权限或直接输入文字')
  },
  onEnd: () => { listening.value = false },
})

const modeFromRoute = computed<Mode>(() => {
  const mode = String(route.query.mode || 'courseware') as Mode
  return ['courseware', 'exam', 'exercise', 'lesson', 'animation', 'analytics'].includes(mode) ? mode : 'courseware'
})

const activeMode = computed(() => modeFromRoute.value)

const taskTabs = [
  { mode: 'exam', label: 'AI命题', icon: 'Finished' },
  { mode: 'exercise', label: 'AI组题', icon: 'List' },
  { mode: 'lesson', label: 'AI教案 · 大单元', icon: 'Tickets' },
] as const

const creatorChips = [
  { mode: 'animation', label: '教学动画', icon: 'Film' },
  { mode: 'exercise', label: '教学游戏', icon: 'Trophy' },
  { mode: 'exam', label: 'AI命题', icon: 'Finished' },
  { mode: 'lesson', label: '大单元教案', icon: 'Tickets' },
  { mode: 'courseware', label: '互动课件', icon: 'Document' },
  { mode: 'analytics', label: '数据回收', icon: 'DataLine' },
] as const

const modeConfigs: Record<string, any> = {
  courseware: {
    label: 'AI互动课件',
    shortLabel: '互动课件',
    icon: 'MagicStick',
    placeholder: '教学游戏｜以《西游记》取经之路为故事线，生成六年级课内古诗词闯关游戏，让学生在游戏化体验中变“被动背诵”为“主动探究”。',
    floatPlaceholder: '帮我生成初英人教七下U1 Grammar Focus的互动课件，通过精简而高效的课堂活动练习because的用法。',
  },
  exam: {
    label: 'AI命题',
    icon: 'Finished',
    tip: '上传命题素材的资料和要求，AI即可命制一道原创且专业的题目。',
    inputPlaceholder: '请输入内容',
    previewText: '请根据chinadaily这篇文章，帮我命制北京英语中考阅读理解模拟题。',
    examples: [
      { prompt: '根据我上传的ChinaDaily这篇文章，帮我命制北京英语中考阅读理解模拟题', heat: 27466, hot: true },
      { prompt: '请你找一篇适合中学生读的冰心散文，出一道中考记叙文阅读', heat: 26197, hot: true },
      { prompt: '根据人民日报“人工智能”主题报道，出一道北京西城区六年级难度应用题', heat: 24937 },
      { prompt: '结合古代科技相关情境，出一道“密度相关”中考难度的物理计算题', heat: 24250 },
    ],
  },
  exercise: {
    label: 'AI组题',
    icon: 'List',
    tip: '输入组题的知识点范围难度等要求，AI即可从海量题库智能挑选组成一份题单。',
    inputPlaceholder: '请输入内容',
    previewText: '帮我按二次函数压轴题和模拟题中考查方式，组一份有难度梯度的练习。',
    examples: [
      { prompt: '结合过往三年北京中考题和模拟题中考查“二次函数”的真题，组一份有难度梯度的专项练习', heat: 27105, hot: true },
      { prompt: '根据图中这名同学的错题，为他进行错因分析并组一套针对性练习', heat: 25882, hot: true },
      { prompt: '结合北上广深近三年中考语文的文言文阅读题，组一份题单，至少30题', heat: 24302 },
      { prompt: '我是广州一名初中英语老师，请帮我找过去五年广州中考英语真题', heat: 23898 },
    ],
  },
  lesson: {
    label: 'AI教案 · 大单元',
    icon: 'Tickets',
    tip: '输入课程单元等信息，AI即可生成一份专业的大单元教案设计。',
    inputPlaceholder: '请输入内容',
    previewText: '帮我出一份课时教学设计，关于人教版新一上第四单元11-20的认识。',
    examples: [
      { prompt: '帮我出一份课时教学设计，关于人教版新一上第四单元11~20的认识第1课时', heat: 27347, hot: true },
      { prompt: '基于这份教案进行修改，在“0的意义”的部分更体现游戏化教学', heat: 27190, hot: true },
      { prompt: '结合“我校的玉兰树春天开花”这一情境，帮我生成语文部编版七上第一单元教案', heat: 24961 },
      { prompt: '基于这份教案进行修改，不改变其他内容，在一个环节中增加使用AI工具', heat: 24025 },
    ],
  },
  animation: {
    label: '教学动画',
    shortLabel: '教学动画',
    icon: 'Film',
    placeholder: '用动画演示二次函数 y=ax²+bx+c 的图像随参数 a、b、c 变化的过程，包含坐标轴、参数滑块和课堂提问。',
    floatPlaceholder: '说出一个知识点，生成可投屏的教学动画。',
    tip: '把抽象概念、实验过程或知识推演转成可播放的课堂动画。',
    inputPlaceholder: '请输入动画主题或上传图片/材料后生成动画',
    previewText: '展示圆柱体积公式从切拼到推导的全过程。',
    examples: [
      { prompt: '展示二次函数 y=ax²+bx+c 的图像随参数 a、b、c 变化的过程', heat: 28120, hot: true },
      { prompt: '用动画演示圆柱体积公式推导，突出底面积和高的关系', heat: 26788, hot: true },
      { prompt: '用动画解释光合作用中水、二氧化碳、光照和氧气的变化', heat: 24806 },
    ],
  },
  analytics: {
    label: '课堂数据回收',
    shortLabel: '数据回收',
    icon: 'DataLine',
    placeholder: '设计一个课堂数据回收活动，收集学生对圆柱体积公式的理解程度、易错点和课后反馈。',
    floatPlaceholder: '描述你要收集的课堂反馈或答题数据。',
    tip: '创建投票、问答、测评等活动，课堂上实时收集学生反馈。',
    inputPlaceholder: '请输入课堂数据回收目标',
    previewText: '收集学生对本节课知识点掌握程度，并统计正确率和高频错因。',
    examples: [
      { prompt: '创建一个课堂即时反馈，统计学生对圆柱体积公式的掌握程度', heat: 23340, hot: true },
      { prompt: '设计一个课后 exit ticket，收集学生最困惑的问题和自评等级', heat: 21902 },
      { prompt: '为英语阅读课创建投票和简答回收，分析学生对文章主旨的理解', heat: 20660 },
    ],
  },
}

const activeConfig = computed(() => modeConfigs[activeMode.value] || modeConfigs.courseware)
const previewTabs = computed(() => {
  const base = [
    { mode: 'exam', label: 'AI命题' },
    { mode: 'exercise', label: 'AI组题' },
    { mode: 'lesson', label: 'AI教案' },
  ]
  if (['exam', 'exercise', 'lesson'].includes(activeMode.value)) return base
  return [
    { mode: 'animation', label: '教学动画' },
    { mode: 'courseware', label: '互动课件' },
    { mode: 'analytics', label: '数据回收' },
  ]
})

const categories = ['推荐', '语文', '数学', '英语', '物理', '化学', '信息科技', '课堂工具', '学前教育', '高等教育', '职业教育', '其他']

const resources = [
  { id: 'guide', category: '推荐', title: '新手指引', author: 'TeacherYO', likes: 6266, views: '9.2万', kicker: 'AI TEACHING', coverTitle: '新手使用攻略', coverSub: '一句话生成专业级教学动画，让教学更生动', coverClass: 'green', visual: 'chart', avatar: '#8B5E34' },
  { id: 'tips', category: '课堂工具', hot: true, title: '【玩转互动课件】必看小技巧', author: 'TeacherYO', likes: 6108, views: '7.9万', kicker: '快速入门', coverTitle: '玩转互动课件', coverSub: '必看小技巧', coverClass: 'yellow', visual: 'slides', avatar: '#8B5E34' },
  { id: 'data', category: '课堂工具', hot: true, title: '【数据回收】新手指引', author: 'TeacherYO', likes: 6036, views: '6.7万', kicker: '课堂工具', coverTitle: '玩转数据回收', coverSub: '案例合集', coverClass: 'mint', visual: 'chart', avatar: '#8B5E34' },
  { id: 'case', category: '推荐', hot: true, title: '【持续更新】智教助手经典案例解析合集', author: 'TeacherYO', likes: 5925, views: '8.9万', kicker: '案例解析', coverTitle: '经典案例解析系列合集', coverSub: '想学习那些课件怎么做？', coverClass: 'blue', visual: 'slides', avatar: '#8B5E34' },
  { id: 'english-food', category: '英语', hot: true, title: 'Unit4 Healthy Food 第一课时', author: '海淀老师勇闯AI圈', likes: 5914, views: '7万', kicker: 'Unit 4 Healthy Food', coverTitle: "Let's speak English!", coverSub: 'Start', coverClass: 'english', visual: 'people', avatar: '#C08457' },
  { id: 'cylinder', category: '数学', hot: true, title: '【互动课件】小学数学六年级圆柱的体积', author: '小叶老师用AI', likes: 5569, views: '8万', kicker: '小学数学 人教版六年级下册', coverTitle: '圆柱的体积', coverSub: '天坛 · 祈年殿', coverClass: 'cream', visual: 'tower', avatar: '#5B8DEF' },
  { id: 'oral', category: '语文', featured: true, title: '一年级烟花口算', author: '智教用户0227', likes: 5553, views: '5.7万', kicker: '数学游戏', coverTitle: '星空烟花口算', coverSub: '开始练习', coverClass: 'space', visual: 'grid', avatar: '#94a3b8' },
  { id: 'vision', category: '信息科技', hot: true, title: 'AI如何“看”世界 —— 揭秘图像识别', author: '蒋老师的AI实验室', likes: 5479, views: '5.8万', kicker: '人工智能体验课', coverTitle: 'AI如何“看”世界？', coverSub: '揭秘图像识别的工作过程', coverClass: 'dark', visual: 'grid', avatar: '#B08968' },
  { id: 'festival', category: '语文', hot: true, title: '《祝福》教学动画（4.9号已更新）', author: '巧克力麦片', likes: 5413, views: '7.3万', kicker: '文学作品', coverTitle: '《祝福》', coverSub: '鲁迅小说中的悲剧意味', coverClass: 'night', visual: 'festival', avatar: '#e11d48' },
  { id: 'ranking', category: '历史', hot: true, title: '大明书院科举榜', author: '智教用户', likes: 5370, views: '8万', kicker: '历史课堂', coverTitle: '大明书院科举榜', coverSub: '排行榜互动游戏', coverClass: 'green', visual: 'shape', avatar: '#0f766e' },
  { id: 'number', category: '数学', hot: true, title: '大数的认识', author: '智教用户', likes: 5320, views: '5.9万', kicker: 'DIGITAL RECOVERY', coverTitle: '大数的认识', coverSub: 'ACCESS SYSTEM', coverClass: 'cyber', visual: 'grid', avatar: '#2563eb' },
  { id: 'cave', category: '语文', hot: true, title: '《记金华的双龙洞》互动课件61', author: '智教用户', likes: 5299, views: '5.8万', kicker: '游记阅读', coverTitle: '记金华的双龙洞', coverSub: '跟着叶圣陶先生拜访洞中奇景', coverClass: 'cave', visual: 'cave', avatar: '#b45309' },
]

const caseTabs = [
  { mode: 'all', label: '全部案例' },
  { mode: 'exam', label: 'AI命题' },
  { mode: 'exercise', label: 'AI组题' },
  { mode: 'lesson', label: 'AI教案 · 大单元' },
]

const cases = [
  { mode: 'exercise', type: 'AI组题', title: '错因分析并组针对性练习', file: '三角形花坛装饰瓷砖问题错因分析与针对...', theme: 'blue' },
  { mode: 'exam', type: 'AI命题', title: '生成中考叙述文阅读题', file: '长辈教诲晚辈悟守人生信条 中考记...', theme: 'green' },
  { mode: 'lesson', type: 'AI教案 · 大单元', title: '人教版七上第二章有理数运算教学...', file: '人教版七年级上册第二章 有理数的运...', theme: 'yellow' },
  { mode: 'exam', type: 'AI命题', title: '天干地支中等难度周期解答题', file: '天干地支周期问题解答题.docx', theme: 'green' },
  { mode: 'exercise', type: 'AI组题', title: '查找北京中考字形高频题', file: '北京地区近3年中考及一模二模字形考查...', theme: 'blue' },
  { mode: 'lesson', type: 'AI教案 · 大单元', title: '设计人教版七上整式加减教学方案', file: '人教版七上第四章《整式的加减》第二...', theme: 'yellow' },
  { mode: 'exam', type: 'AI命题', title: '生成中国航天反比例函数应用题', file: '中国航天相关反比例函数应用题.docx', theme: 'green' },
  { mode: 'exercise', type: 'AI组题', title: '整理近3年北京中考信息匹配题', file: '近3年北京中考英语真题信息匹配题汇总...', theme: 'blue' },
]

const filteredResources = computed(() => {
  const kw = keyword.value.trim().toLowerCase()
  return resources.filter(item => {
    const categoryOk = activeCategory.value === '推荐' || item.category === activeCategory.value
    const keywordOk = !kw || `${item.title}${item.author}${item.coverTitle}${item.category}`.toLowerCase().includes(kw)
    return categoryOk && keywordOk
  })
})

const filteredCases = computed(() => {
  return caseFilter.value === 'all' ? cases : cases.filter(item => item.mode === caseFilter.value)
})

watch(() => route.query.mode, () => {
  prompt.value = ''
})

function setMode(mode: Mode) {
  router.push({ path: '/', query: { mode } })
}

function modePath(mode: string) {
  if (mode === 'exam') return '/exam'
  if (mode === 'exercise') return '/exercise'
  if (mode === 'lesson') return '/lesson-plan'
  if (mode === 'animation') return '/animation'
  if (mode === 'analytics') return '/classroom'
  return '/courseware/create'
}

function startCreate() {
  const basePrompt = prompt.value.trim() || activeConfig.value.placeholder || activeConfig.value.examples?.[0]?.prompt || ''
  const text = `${basePrompt}${buildMaterialPromptBlock(uploadedMaterials.value, '参考素材')}`.trim()
  localStorage.setItem('quick_create_prompt', text)
  router.push(modePath(activeMode.value))
}

function applyPromptTemplate(item: any) {
  prompt.value = item.prompt
}

function pickFile(type: 'file' | 'image') {
  uploadAccept.value = type === 'image' ? 'image/*' : '.txt,.md,.csv,.json,.docx,.pptx,.pdf,.xlsx'
  fileInputRef.value?.click()
}

async function handleFileChange(event: Event) {
  const file = (event.target as HTMLInputElement).files?.[0]
  if (!file) return
  try {
    const parsed: any = await parseMaterial(file)
    userStore.refreshCreditsFromResponse(parsed)
    const data = parsed.data || parsed
    uploadedMaterials.value.push(fileParseToContext(file, data))
    ElMessage.success('材料已解析并加入任务')
  } catch {
    await addFallbackMaterial(file)
  } finally {
    ;(event.target as HTMLInputElement).value = ''
  }
}

function inferTypeLabel(filename: string) {
  const ext = filename.toLowerCase().split('.').pop() || ''
  if (ext === 'pptx') return 'PPT材料'
  if (ext === 'pdf') return 'PDF材料'
  if (ext === 'xlsx' || ext === 'xls' || ext === 'csv') return '表格材料'
  return 'Word材料'
}

async function addFallbackMaterial(file: File) {
  if (file.type.startsWith('image/')) {
    uploadedMaterials.value.push({
      id: `${Date.now()}-${file.name}`,
      name: file.name,
      icon: 'Picture',
      typeLabel: '图片',
      sizeLabel: formatMaterialFileSize(file.size),
      excerpt: '请根据图片内容识别知识点、题目信息或板书结构。',
    })
  } else if (/\.(docx|pptx|pdf|xlsx|xls)$/i.test(file.name)) {
    uploadedMaterials.value.push({
      id: `${Date.now()}-${file.name}`,
      name: file.name,
      icon: 'Document',
      typeLabel: inferTypeLabel(file.name),
      sizeLabel: formatMaterialFileSize(file.size),
      excerpt: '该材料暂未解析成功，请结合文件名和当前输入要求生成教学内容。',
    })
  } else {
    const text = await file.text()
    uploadedMaterials.value.push({
      id: `${Date.now()}-${file.name}`,
      name: file.name,
      icon: 'Document',
      typeLabel: '文本材料',
      sizeLabel: formatMaterialFileSize(file.size),
      excerpt: text.slice(0, 4000),
    })
  }
  ElMessage.warning('材料解析失败，已改用本地摘要')
}

function removeMaterial(id: string) {
  uploadedMaterials.value = uploadedMaterials.value.filter(item => item.id !== id)
}

function toggleVoice() {
  if (listening.value) {
    speech.stop()
    return
  }
  if (!speech.isSupported()) {
    ElMessage.warning('当前浏览器不支持语音识别，请使用 Chrome/Edge 或直接输入文字')
    return
  }
  speech.start()
}

function openResource(item: any) {
  const demoMap: Record<string, string> = {
    'english-food': 'food',
    oral: 'data',
    ranking: 'case',
    number: 'vision',
    festival: 'guide',
    cave: 'cylinder',
  }
  router.push(`/demo/${demoMap[item.id] || item.id}`)
}

function goResourceSearch() {
  const kw = keyword.value.trim()
  router.push({ path: '/resources', query: kw ? { keyword: kw } : undefined })
}
</script>

<style scoped>
.zj-home {
  min-height: 100vh;
  color: #173f35;
  background: #f8faf7;
}

.courseware-shell {
  min-height: 100vh;
  padding: 46px 52px 80px;
}

.top-composer,
.resource-toolbar,
.resource-grid {
  width: min(100%, 1474px);
  margin-left: auto;
  margin-right: auto;
}

.top-composer {
  margin-bottom: 38px;
}

.composer-title {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-bottom: 24px;
}

.mascot {
  width: 38px;
  height: 38px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid #dbe8de;
  border-radius: 50%;
  background: #fff;
  color: #0f4f3e;
  font-size: 20px;
  flex-shrink: 0;
}

.mascot.large {
  width: 44px;
  height: 44px;
}

.composer-title h1,
.task-heading h1 {
  margin: 0;
  color: #164f3e;
  font-size: 24px;
  font-weight: 900;
  letter-spacing: 0;
}

.prompt-card {
  min-height: 148px;
  border: 1px solid #cfe0d3;
  border-radius: 18px;
  background: rgba(255, 255, 255, 0.86);
  box-shadow: 0 18px 42px rgba(17, 69, 52, 0.07);
  padding: 22px 24px 15px;
}

.prompt-card textarea,
.task-input-card textarea {
  width: 100%;
  resize: none;
  border: none;
  outline: none;
  background: transparent;
  color: #173f35;
  font-family: inherit;
  letter-spacing: 0;
}

.prompt-card textarea {
  height: 62px;
  font-size: 16px;
  line-height: 1.75;
}

.prompt-card textarea::placeholder,
.task-input-card textarea::placeholder,
.floating-composer input::placeholder {
  color: #a7b2ab;
}

.materials-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 4px 0 11px;
}

.task-materials-row {
  margin-top: 8px;
}

.materials-row span {
  min-width: 0;
  height: 30px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: 1px solid #dbe8de;
  border-radius: 15px;
  background: #f6fbf6;
  color: #31584d;
  padding: 0 8px 0 11px;
  font-size: 12px;
  font-weight: 800;
}

.materials-row button {
  border: none;
  background: transparent;
  color: #78908a;
  cursor: pointer;
}

.hidden-input {
  display: none;
}

.prompt-toolbar,
.task-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
}

.toolbar-left,
.toolbar-right,
.task-toolbar > div {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

.prompt-toolbar button,
.task-toolbar button,
.floating-composer button {
  height: 39px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid #dfebe2;
  border-radius: 20px;
  background: #fff;
  color: #51665f;
  padding: 0 13px;
  font-size: 14px;
  cursor: pointer;
}

.prompt-toolbar button:first-child,
.prompt-toolbar button:nth-child(2),
.voice-btn {
  width: 39px;
  padding: 0;
}

.chip-btn {
  gap: 6px;
  font-weight: 800;
}

.chip-btn.active,
.chip-btn:hover,
.voice-btn:hover,
.voice-btn.active {
  border-color: #b4d6bd;
  background: #f5fbf5;
  color: #0f4f3e;
}

.send-btn,
.prompt-toolbar .send-btn,
.floating-composer .send-btn {
  width: 40px;
  border: none;
  border-radius: 13px;
  background: #0f5a42;
  color: #fff;
  padding: 0;
}

.send-btn.muted {
  background: #9aa7a0;
}

.resource-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 22px;
  margin-bottom: 16px;
}

.category-tabs {
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 30px;
  overflow-x: auto;
  scrollbar-width: none;
}

.category-tabs::-webkit-scrollbar {
  display: none;
}

.category-tabs button {
  position: relative;
  border: none;
  background: transparent;
  color: #47635a;
  font-size: 14px;
  white-space: nowrap;
  cursor: pointer;
  padding: 8px 0;
}

.category-tabs button.active {
  color: #00543d;
  font-weight: 900;
}

.category-tabs button.active::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 3px;
  height: 3px;
  border-radius: 2px;
  background: #00543d;
}

.hot-mini {
  margin-left: 2px;
  color: #ff4b20;
  font-size: 9px;
  font-weight: 900;
}

.search-pill {
  width: 220px;
  height: 36px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  gap: 8px;
  border-radius: 18px;
  background: #eef1ec;
  color: #a5aea7;
  padding: 0 14px;
}

.search-pill input {
  min-width: 0;
  flex: 1;
  border: none;
  outline: none;
  background: transparent;
  color: #173f35;
  font-size: 13px;
}

.resource-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(240px, 1fr));
  gap: 24px;
}

.resource-card {
  min-width: 0;
  overflow: hidden;
  border: 1px solid #e1e8e2;
  border-radius: 14px;
  background: #fff;
  cursor: pointer;
  transition: transform .18s ease, box-shadow .18s ease;
}

.resource-card:hover {
  transform: translateY(-3px);
  box-shadow: 0 12px 24px rgba(17, 69, 52, 0.1);
}

.cover {
  position: relative;
  height: 190px;
  overflow: hidden;
  border-radius: 10px;
  margin: 5px;
  padding: 24px;
}

.hot-badge,
.views {
  position: absolute;
  z-index: 2;
  height: 24px;
  display: inline-flex;
  align-items: center;
  border-radius: 12px;
  font-size: 12px;
  font-weight: 900;
}

.hot-badge {
  top: 8px;
  left: 8px;
  background: #fff;
  color: #ff4b20;
  padding: 0 8px;
}

.hot-badge.featured {
  color: #d97706;
}

.views {
  top: 8px;
  right: 8px;
  gap: 4px;
  background: rgba(0, 0, 0, .26);
  color: #fff;
  padding: 0 9px;
}

.cover-content {
  position: relative;
  z-index: 1;
  max-width: 74%;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.cover-content small {
  color: inherit;
  opacity: .76;
  font-size: 12px;
}

.cover-content strong {
  font-size: 25px;
  line-height: 1.18;
  font-weight: 900;
  letter-spacing: 0;
}

.cover-content em {
  font-style: normal;
  font-size: 13px;
  line-height: 1.4;
}

.card-body {
  padding: 10px 16px 14px;
}

.card-body h3 {
  min-height: 22px;
  color: #233c35;
  font-size: 16px;
  font-weight: 500;
  line-height: 1.4;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.author-row {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 8px;
  color: #87958f;
  font-size: 13px;
}

.avatar-dot {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  flex-shrink: 0;
}

.star {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

.floating-composer {
  position: fixed;
  left: calc(var(--active-sidebar-width, var(--sidebar-width)) + 450px);
  right: 450px;
  bottom: 20px;
  z-index: 15;
  height: 76px;
  min-width: 520px;
  display: flex;
  align-items: center;
  gap: 6px;
  border: 1px solid #cfe0d3;
  border-radius: 18px;
  background: rgba(255, 255, 255, .94);
  box-shadow: 0 12px 34px rgba(17, 69, 52, .12);
  padding: 0 16px 0 22px;
}

.floating-composer span {
  color: #a0aaa4;
  white-space: nowrap;
}

.floating-composer input {
  min-width: 0;
  flex: 1;
  border: none;
  outline: none;
  background: transparent;
  color: #173f35;
  font-size: 15px;
}

.task-shell {
  min-height: 100vh;
  padding: 148px 42px 76px;
}

.task-center {
  width: min(100%, 940px);
  margin: 0 auto;
}

.task-heading {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  margin-bottom: 38px;
}

.task-heading h1 {
  font-size: 32px;
}

.task-workbench {
  display: grid;
  grid-template-columns: 340px minmax(0, 720px);
  align-items: center;
  justify-content: center;
  gap: 16px;
}

.tip-card {
  position: relative;
  min-height: 344px;
  border-radius: 13px;
  background: #164f3e;
  color: #fff;
  padding: 17px 15px 16px;
}

.tip-card::after {
  content: "";
  position: absolute;
  right: -8px;
  top: 78px;
  border-left: 8px solid #164f3e;
  border-top: 7px solid transparent;
  border-bottom: 7px solid transparent;
}

.tip-card.exercise {
  background: #1f526f;
}

.tip-card.exercise::after {
  border-left-color: #1f526f;
}

.tip-card.lesson {
  background: #755300;
}

.tip-card.lesson::after {
  border-left-color: #755300;
}

.tip-title {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 13px;
}

.tip-title strong {
  font-size: 14px;
}

.tip-title span {
  height: 18px;
  display: inline-flex;
  align-items: center;
  border-radius: 4px;
  background: #ff5b2e;
  padding: 0 5px;
  font-size: 10px;
  font-weight: 900;
}

.tip-card > p {
  min-height: 63px;
  margin: 0;
  font-size: 16px;
  line-height: 1.52;
  font-weight: 900;
}

.tip-preview {
  height: 176px;
  margin-top: 12px;
  overflow: hidden;
  border-radius: 10px;
  background: #fff;
  color: #173f35;
  padding: 0 14px 14px;
}

.mini-tabs {
  height: 35px;
  display: flex;
  justify-content: space-around;
  align-items: center;
  margin: 0 -14px 14px;
  background: #f0f6ee;
  color: #8a9992;
  font-size: 12px;
  font-weight: 900;
}

.mini-tabs span.active {
  color: #0f4f3e;
  border-bottom: 2px solid #0f4f3e;
}

.doc-chip {
  width: 164px;
  height: 47px;
  display: grid;
  justify-content: center;
  border-radius: 8px;
  background: #f4f6f7;
  margin: 2px 0 12px 20px;
  padding: 7px 9px;
}

.doc-chip strong {
  font-size: 12px;
}

.doc-chip small {
  color: #9aa7a0;
}

.tip-preview p {
  color: #173f35;
  font-size: 14px;
  line-height: 1.6;
}

.tip-actions {
  display: grid;
  grid-template-columns: .48fr 1fr;
  gap: 9px;
  margin-top: 16px;
}

.tip-actions button {
  height: 32px;
  border: none;
  border-radius: 16px;
  background: rgba(255,255,255,.24);
  color: #fff;
  font-weight: 900;
  cursor: pointer;
}

.tip-actions button:last-child {
  background: #dff6d8;
  color: #164f3e;
}

.task-main {
  min-width: 0;
}

.task-tabs {
  height: 49px;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  border: 1px solid #cfe0d3;
  border-bottom: none;
  border-radius: 18px 18px 0 0;
  background: #f1f6ef;
  overflow: hidden;
}

.task-tabs button {
  position: relative;
  border: none;
  background: transparent;
  color: #637a72;
  font-size: 15px;
  font-weight: 900;
  cursor: pointer;
}

.task-tabs button.active {
  color: #0f4f3e;
}

.task-tabs button.active::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: 0;
  width: 26px;
  height: 2px;
  transform: translateX(-50%);
  background: #0f4f3e;
}

.task-input-card {
  min-height: 148px;
  border: 1px solid #cfe0d3;
  border-radius: 0 0 18px 18px;
  background: rgba(255,255,255,.84);
  box-shadow: 0 18px 42px rgba(17, 69, 52, 0.07);
  padding: 23px 22px 16px;
}

.task-input-card textarea {
  height: 55px;
  font-size: 16px;
  line-height: 1.55;
}

.hot-prompts {
  margin-top: 22px;
}

.hot-prompts h2 {
  margin: 0 0 14px;
  font-size: 16px;
  color: #164f3e;
}

.hot-prompts button {
  width: 100%;
  min-height: 44px;
  display: grid;
  grid-template-columns: 21px minmax(0, 1fr) auto 92px;
  align-items: center;
  gap: 7px;
  border: none;
  background: transparent;
  color: #50665e;
  text-align: left;
  cursor: pointer;
  font-size: 15px;
}

.hot-prompts button span {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.hot-prompts em {
  border: 1px solid #ff7f5c;
  border-radius: 4px;
  color: #ff5b2e;
  padding: 0 4px;
  font-style: normal;
  font-size: 12px;
}

.hot-prompts small {
  color: #9aa7a0;
  text-align: right;
  font-size: 12px;
}

.case-section {
  width: min(100%, 1138px);
  margin: 208px auto 0;
}

.case-tabs {
  height: 36px;
  width: min(100%, 720px);
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  align-items: center;
  border-radius: 18px;
  background: #eef5ee;
  margin: 0 auto 28px;
  padding: 3px;
}

.case-tabs button {
  height: 30px;
  border: none;
  border-radius: 15px;
  background: transparent;
  color: #6a7f77;
  font-weight: 900;
  cursor: pointer;
}

.case-tabs button.active {
  background: #fff;
  color: #0f4f3e;
}

.case-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(190px, 1fr));
  gap: 16px 22px;
}

.case-card {
  min-width: 0;
  border-radius: 8px;
  background: #fff;
  padding: 7px;
}

.case-cover {
  height: 153px;
  overflow: hidden;
  border-radius: 7px;
  padding: 7px;
}

.case-cover span {
  display: inline-flex;
  height: 24px;
  align-items: center;
  border-radius: 4px;
  background: rgba(255,255,255,.65);
  padding: 0 6px;
  font-size: 13px;
  font-weight: 900;
}

.case-cover div {
  width: 80%;
  height: 76%;
  margin: 15px auto 0;
  border-radius: 7px;
  background: #fff;
}

.case-card h3 {
  margin: 10px 7px 6px;
  color: #173f35;
  font-size: 16px;
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.case-card p {
  display: flex;
  align-items: center;
  gap: 5px;
  margin: 0 7px 8px;
  color: #7f8d87;
  font-size: 12px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.green {
  color: #fff;
  background: radial-gradient(circle at 78% 70%, rgba(101,255,0,.58), transparent 22%), linear-gradient(135deg, #063a2d, #00854f);
}

.yellow {
  color: #714a00;
  background: radial-gradient(circle at 82% 50%, rgba(255,255,255,.55), transparent 28%), linear-gradient(135deg, #fff2a8, #ffd84d);
}

.mint {
  color: #00543d;
  background: linear-gradient(90deg, rgba(255,255,255,.74), rgba(255,255,255,.1)), linear-gradient(135deg, #e7ffe9, #dff7e5);
}

.blue {
  color: #003f68;
  background: linear-gradient(135deg, #dbe8ff, #c8ddff);
}

.english {
  color: #f48b00;
  background: radial-gradient(circle at 28% 70%, rgba(255,255,255,.65), transparent 32%), linear-gradient(135deg, #f9e0b9, #eed0a8);
}

.cream {
  color: #7a5600;
  background: linear-gradient(135deg, #fff3c4, #f7e3a1);
}

.dark,
.cyber {
  color: #fff;
  background: radial-gradient(circle at 70% 46%, rgba(0,195,255,.26), transparent 28%), linear-gradient(135deg, #050505, #111827);
}

.space {
  color: #fff;
  background: radial-gradient(circle at 60% 40%, rgba(143,125,255,.46), transparent 30%), linear-gradient(135deg, #15162b, #48438f);
}

.night {
  color: #fff;
  background: linear-gradient(135deg, #101828, #3a1f1f);
}

.cave {
  color: #4b2b00;
  background: linear-gradient(135deg, #e7bd74, #6d4216);
}

.mini-slides {
  position: absolute;
  right: 18px;
  top: 44px;
  display: grid;
  gap: 8px;
}

.mini-slides span {
  width: 90px;
  height: 42px;
  border-radius: 7px;
  background: rgba(255,255,255,.78);
  box-shadow: 0 5px 12px rgba(0,0,0,.16);
}

.chart-art {
  position: absolute;
  right: 28px;
  bottom: 24px;
  display: flex;
  align-items: flex-end;
  gap: 8px;
}

.chart-art span {
  width: 24px;
  border-radius: 5px 5px 0 0;
  background: rgba(255,255,255,.58);
}

.chart-art span:nth-child(1) { height: 42px; }
.chart-art span:nth-child(2) { height: 76px; }
.chart-art span:nth-child(3) { height: 56px; }

.tower-art {
  position: absolute;
  right: 34px;
  bottom: 26px;
  width: 112px;
  height: 118px;
  background:
    linear-gradient(#0a6b7b, #0a6b7b) 28px 0 / 56px 13px no-repeat,
    linear-gradient(#be5b2c, #be5b2c) 18px 28px / 76px 16px no-repeat,
    linear-gradient(#0a6b7b, #0a6b7b) 10px 44px / 92px 18px no-repeat,
    linear-gradient(#be5b2c, #be5b2c) 24px 72px / 64px 18px no-repeat,
    linear-gradient(#e8dcc5, #e8dcc5) 0 94px / 112px 22px no-repeat;
  border-radius: 50% 50% 4px 4px;
}

.people-art {
  position: absolute;
  right: 22px;
  bottom: 16px;
  display: flex;
  align-items: flex-end;
  gap: 14px;
}

.people-art span {
  width: 62px;
  height: 92px;
  border-radius: 30px 30px 12px 12px;
  background: rgba(255,255,255,.55);
}

.people-art span:nth-child(2) {
  width: 48px;
  height: 72px;
}

.shape-art {
  position: absolute;
  right: 18px;
  bottom: 22px;
  width: 150px;
  height: 110px;
}

.shape-art span {
  position: absolute;
  display: block;
  border-radius: 50%;
}

.shape-art span:nth-child(1) {
  width: 96px;
  height: 96px;
  right: 12px;
  bottom: 0;
  background: #9ed797;
}

.shape-art span:nth-child(2) {
  width: 72px;
  height: 72px;
  left: 0;
  bottom: 8px;
  background: #b8d1ff;
}

.shape-art span:nth-child(3) {
  width: 0;
  height: 0;
  left: 16px;
  top: 2px;
  border-left: 18px solid transparent;
  border-right: 18px solid transparent;
  border-bottom: 36px solid #ff6b2b;
  border-radius: 0;
  background: transparent;
}

.grid-art {
  position: absolute;
  inset: 0;
  opacity: .55;
  background-image:
    linear-gradient(rgba(0,195,255,.18) 1px, transparent 1px),
    linear-gradient(90deg, rgba(0,195,255,.18) 1px, transparent 1px);
  background-size: 30px 30px;
}

.grid-art span {
  position: absolute;
  width: 54px;
  height: 36px;
  border: 1px solid rgba(0,225,255,.35);
  background: rgba(0,225,255,.08);
}

.grid-art span:nth-child(1) { left: 18%; top: 25%; }
.grid-art span:nth-child(2) { left: 55%; top: 18%; }
.grid-art span:nth-child(3) { left: 36%; top: 58%; }
.grid-art span:nth-child(4) { left: 72%; top: 62%; }

.cave-art,
.festival-art {
  position: absolute;
  inset: 0;
  opacity: .42;
}

.cave-art {
  background: radial-gradient(ellipse at 50% 76%, rgba(255,225,143,.78), transparent 34%), radial-gradient(ellipse at 50% -10%, rgba(0,0,0,.52), transparent 44%);
}

.festival-art {
  background: radial-gradient(circle at 20% 25%, rgba(220,38,38,.56), transparent 10%), radial-gradient(circle at 78% 32%, rgba(220,38,38,.46), transparent 11%);
}

@media (max-width: 1380px) {
  .resource-grid,
  .case-grid {
    grid-template-columns: repeat(3, minmax(220px, 1fr));
  }

  .floating-composer {
    left: calc(var(--active-sidebar-width, var(--sidebar-width)) + 220px);
    right: 220px;
  }
}

@media (max-width: 1080px) {
  .courseware-shell {
    padding: 30px 28px 80px;
  }

  .resource-grid,
  .case-grid {
    grid-template-columns: repeat(2, minmax(220px, 1fr));
  }

  .task-workbench {
    grid-template-columns: 1fr;
  }

  .tip-card {
    display: none;
  }

  .floating-composer {
    left: calc(var(--active-sidebar-width, var(--sidebar-width)) + 30px);
    right: 30px;
    min-width: 0;
  }
}

@media (max-width: 760px) {
  .courseware-shell,
  .task-shell {
    padding: 20px 14px 90px;
  }

  .resource-toolbar,
  .prompt-toolbar,
  .task-toolbar {
    align-items: stretch;
    flex-direction: column;
  }

  .search-pill {
    width: 100%;
  }

  .resource-grid,
  .case-grid {
    grid-template-columns: 1fr;
  }

  .floating-composer {
    left: 96px;
    right: 12px;
  }
}
</style>
