<template>
  <Modal
    :visible="visible"
    :width="1120"
    :close-button="true"
    :close-on-click-mask="!working"
    @update:visible="value => emit('update:visible', value)"
  >
    <div class="ai-dialog">
      <div class="header">
        <div>
          <div class="title">{{ pageTitle }}</div>
          <div class="sub">{{ pageMeta }}</div>
        </div>
      </div>

      <div v-if="outlineLoading" class="loading-strip">
        <span class="loading-dot"></span>
        <span>正在生成大纲，请稍候</span>
      </div>

      <div v-else-if="taskInfo" class="progress-strip">
        <div class="current-step">{{ currentProgressLabel }}</div>
        <div class="progress-line">
          <div class="progress-bar" :style="{ width: `${progressValue}%` }"></div>
        </div>
        <div class="progress-value">{{ progressValue }}%</div>
      </div>

      <div class="extra">
        <div class="label">补充要求</div>
        <TextArea v-model:value="extraPrompt" :rows="2" placeholder="可选，例如：多一些节奏互动，语言更适合小学低年级" :disabled="working" />
      </div>

      <div v-if="outline" class="outline">
        <div class="page-nav">
          <button
            v-for="page in outline.pages"
            :key="page.pageNo"
            class="nav-item"
            :class="{ active: selectedPageNo === page.pageNo }"
            type="button"
            @click="selectedPageNo = page.pageNo"
          >
            <span class="nav-no">{{ formatPageNo(page.pageNo) }}</span>
            <span class="nav-title">{{ page.title || "未命名页面" }}</span>
          </button>
        </div>

        <div v-if="selectedPage" class="page-editor">
          <div class="editor-head">
            <div class="title-editor">
              <input v-model="selectedPage.title" class="page-title" :disabled="working" />
            </div>
          </div>

          <div class="purpose-card">
            <div class="field-title">教学目的</div>
            <input
              v-model="selectedPage.teachingPurpose"
              :disabled="working"
              class="purpose-input"
              placeholder="这一页在课堂中要解决的教学目标"
            />
          </div>

          <div class="field-grid">
            <div class="field-card">
              <div class="field-title">学生看到的内容</div>
              <input
                :value="studentHeadline"
                :disabled="working"
                class="headline-input"
                placeholder="这一页给学生看的核心标题"
                @input="event => updateStudentHeadline(selectedPage!, event)"
              />
              <textarea
                :value="studentPoints.join('\n')"
                :disabled="working"
                class="page-bullets"
                placeholder="每行一条学生可见要点，避免写老师操作步骤"
                @input="event => updateStudentPoints(selectedPage!, event)"
              ></textarea>
            </div>
            <div class="field-card">
              <div class="field-title">课堂活动</div>
              <input
                :value="activityTask"
                :disabled="working"
                class="headline-input"
                placeholder="课堂任务，例如：听辨山谷和小鸟的声音"
                @input="event => updateActivityTask(selectedPage!, event)"
              />
              <textarea
                :value="(selectedPage.activity?.steps || []).join('\n')"
                :disabled="working"
                class="page-bullets"
                placeholder="每行一步课堂操作，供生成活动页或备注使用"
                @input="event => updateActivitySteps(selectedPage!, event)"
              ></textarea>
            </div>
          </div>

          <div class="field-card visual full-field">
              <div class="field-title">设计要求</div>
              <textarea
                v-model="selectedPage.designRequirement"
                :disabled="working"
                class="page-design"
                placeholder="例如：左文右图，右侧放卡通山谷和音符，整体暖色活泼，文字保持大字号。"
              ></textarea>
          </div>

          <div v-if="selectedPage.resourceBindings?.length" class="resource-card">
            <div class="resource-head">
              <div class="field-title">课堂资源</div>
              <div class="resource-hint">生成后可直接播放或展示</div>
            </div>
            <div class="resource-list">
              <div v-for="resource in selectedPage.resourceBindings" :key="`${resource.resourceType}-${resource.resourceId}`" class="resource-item">
                <span class="resource-type">{{ resourceTypeName(resource.resourceType) }}</span>
                <span class="resource-name">{{ resource.name || "已匹配资源" }}</span>
              </div>
            </div>
          </div>

          <div class="keyword-card">
            <div class="keyword-head">
              <div class="keyword-label">图片关键词</div>
              <div class="keyword-hint">用于匹配课件图片，可手动补充或删减</div>
            </div>
            <input
              :value="selectedPage.imageKeywords.join('、')"
              class="keyword-input"
              :disabled="working"
              placeholder="用于检索网络图片，例如：山谷、音乐、卡通、小鸟"
              @input="event => updateImageKeywords(selectedPage!, event)"
            />
          </div>
          <div class="remark-card">
            <div class="remark-head">
              <div class="remark-title">PPT备注</div>
              <div class="remark-hint">仅老师授课时参考，不会显示在幻灯片画面中</div>
            </div>
            <textarea v-model="selectedPage.teacherTips" :disabled="working" class="remark-input"></textarea>
          </div>
        </div>
      </div>

      <div v-else class="empty">生成大纲后，可在这里确认15页结构、页面内容和设计要求。</div>

      <div class="footer">
        <Button @click="emit('update:visible', false)" :disabled="working">取消</Button>
        <Button type="primary" @click="handleOutline" :disabled="working">{{ outline ? "重新生成大纲" : "生成大纲" }}</Button>
        <Button type="primary" @click="handleGenerate" :disabled="!outline || working">确认并生成PPT</Button>
      </div>
    </div>
  </Modal>
</template>

<script lang="ts" setup>
import { ref, computed, watch } from "vue"
import { ElMessage, ElMessageBox } from "element-plus"
import Modal from "@/components/Modal.vue"
import Button from "@/components/Button.vue"
import TextArea from "@/components/TextArea.vue"
import queryParams from "@/queryParams"
import usePptWork from "@/store/pptWork"
import { useSlidesStore } from "@/store"
import useHistorySnapshot from "@/hooks/useHistorySnapshot"
import { httpAjaxErrMsg } from "@/plugins/httpAjax"
import {
  aiCoursewareGenerateApi,
  aiCoursewareOutlineApi,
  aiCoursewareResultApi,
  aiCoursewareTaskApi,
  type AiCoursewareOutline,
  type AiCoursewarePage,
  type AiCoursewareTaskInfo,
  type AiCoursewareGenerateResult
} from "@/api/aiCourseware"
import { aiCoursewareToSlides } from "@/utils/aiCoursewareToSlides"

const props = defineProps<{
  visible: boolean
}>()

const emit = defineEmits<{
  (event: "update:visible", payload: boolean): void
}>()

const pptWork = usePptWork()
const slidesStore = useSlidesStore()
const { addHistorySnapshot } = useHistorySnapshot()

const extraPrompt = ref("")
const outline = ref<AiCoursewareOutline>()
const taskInfo = ref<AiCoursewareTaskInfo>()
const pollTimer = ref<number>()
const selectedPageNo = ref(1)
const outlineLoading = ref(false)
const working = computed(() => outlineLoading.value || taskInfo.value?.status === "PENDING" || taskInfo.value?.status === "RUNNING")
const progressValue = computed(() => taskInfo.value?.progress || 0)
const progressSteps = [
  { threshold: 0, label: "准备中" },
  { threshold: 25, label: "生成内容" },
  { threshold: 50, label: "优化设计" },
  { threshold: 65, label: "匹配图片" },
  { threshold: 100, label: "生成完成" }
]
const currentProgressLabel = computed(() => {
  const matched = [...progressSteps].reverse().find(step => progressValue.value >= step.threshold)
  return shortProgressLabel(taskInfo.value?.message) || matched?.label || "处理中"
})
const pageTitle = computed(() => outline.value?.chapterName || outline.value?.title || "课件大纲")
const pageMeta = computed(() => {
  if (!outline.value) return "根据当前教材、单元和章节生成15页音乐课件"
  return [...[outline.value.gradeName, outline.value.unitName].filter(Boolean), `共${outline.value.pages.length}页`].join(" · ")
})
const selectedPage = computed(() => {
  const pages = outline.value?.pages || []
  return pages.find(page => page.pageNo === selectedPageNo.value) || pages[0]
})
const studentHeadline = computed(() => selectedPage.value?.studentContent?.headline || selectedPage.value?.subtitle || "")
const studentPoints = computed(() => {
  if (!selectedPage.value) return []
  return selectedPage.value.studentContent?.points?.length ? selectedPage.value.studentContent.points : selectedPage.value.bullets || []
})
const activityTask = computed(() => selectedPage.value?.classroomAction?.studentTask || selectedPage.value?.activity?.task || "")

watch(
  () => props.visible,
  visible => {
    if (!visible) clearTask()
  }
)

async function handleOutline() {
  if (!pptWork.id) {
    ElMessage.error("当前课件ID为空")
    return
  }
  outlineLoading.value = true
  const res = await httpAjaxErrMsg(aiCoursewareOutlineApi, {
    id: pptWork.id,
    fromType: queryParams.pptResourcesType || queryParams.fromType,
    extraPrompt: buildExtraPrompt()
  }).finally(() => {
    outlineLoading.value = false
  })
  if (res.code === 200) {
    outline.value = res.data as AiCoursewareOutline
    selectedPageNo.value = outline.value.pages[0]?.pageNo || 1
  }
}

async function handleGenerate() {
  if (!outline.value || !pptWork.id) return
  const confirmed = await ElMessageBox.confirm("生成后会替换当前编辑器中的课件内容，未保存内容将丢失。确认继续？", "确认生成", {
    confirmButtonText: "确认生成",
    cancelButtonText: "取消",
    type: "warning"
  })
    .then(() => true)
    .catch(() => false)
  if (!confirmed) return

  const res = await httpAjaxErrMsg(aiCoursewareGenerateApi, {
    id: pptWork.id,
    fromType: queryParams.pptResourcesType || queryParams.fromType,
    outline: outline.value
  })
  if (res.code !== 200) return

  taskInfo.value = res.data as AiCoursewareTaskInfo
  pollTask(taskInfo.value.taskId)
}

async function pollTask(taskId: string) {
  if (pollTimer.value) window.clearInterval(pollTimer.value)
  await fetchTask(taskId)
  pollTimer.value = window.setInterval(() => fetchTask(taskId), 2000)
}

async function fetchTask(taskId: string) {
  const res = await httpAjaxErrMsg(aiCoursewareTaskApi, taskId)
  if (res.code !== 200) {
    clearTask()
    return
  }
  taskInfo.value = res.data as AiCoursewareTaskInfo
  if (taskInfo.value.status === "DONE") {
    clearPollTimer()
    await applyResult(taskId)
  } else if (taskInfo.value.status === "FAILED") {
    clearPollTimer()
    ElMessage.error(taskInfo.value.message || "AI课件生成失败")
  }
}

function clearTask() {
  clearPollTimer()
  taskInfo.value = undefined
}

function clearPollTimer() {
  if (pollTimer.value) {
    window.clearInterval(pollTimer.value)
    pollTimer.value = undefined
  }
}

async function applyResult(taskId: string) {
  const res = await httpAjaxErrMsg(aiCoursewareResultApi, taskId)
  if (res.code !== 200) return

  const result = res.data as AiCoursewareGenerateResult
  const converted = aiCoursewareToSlides(result.outline)
  slidesStore.setTitle(converted.title)
  slidesStore.setTheme(converted.theme)
  slidesStore.setSlides(converted.slides)
  slidesStore.updateSlideIndex(0)
  addHistorySnapshot()
  ElMessage.success("PPT已生成，请检查后手动保存")
  emit("update:visible", false)
}

function updateStudentHeadline(page: AiCoursewarePage, event: Event) {
  if (!page.studentContent) page.studentContent = { headline: "", points: [] }
  page.studentContent.headline = (event.target as HTMLInputElement).value.trim()
}

function updateStudentPoints(page: AiCoursewarePage, event: Event) {
  if (!page.studentContent) page.studentContent = { headline: "", points: [] }
  const points = (event.target as HTMLTextAreaElement).value
    .split("\n")
    .map(item => item.trim())
    .filter(Boolean)
  page.studentContent.points = points
  page.bullets = points
}

function updateActivityTask(page: AiCoursewarePage, event: Event) {
  if (!page.activity) page.activity = { task: "", steps: [] }
  if (!page.classroomAction) page.classroomAction = { teacherInstruction: "", studentTask: "", interactionType: "" }
  const value = (event.target as HTMLInputElement).value.trim()
  page.activity.task = value
  page.classroomAction.studentTask = value
}

function updateActivitySteps(page: AiCoursewarePage, event: Event) {
  if (!page.activity) page.activity = { task: "", steps: [] }
  page.activity.steps = (event.target as HTMLTextAreaElement).value
    .split("\n")
    .map(item => item.trim())
    .filter(Boolean)
}

function updateImageKeywords(page: AiCoursewarePage, event: Event) {
  page.imageKeywords = (event.target as HTMLInputElement).value
    .split(/[,，、;；\s]+/)
    .map(item => item.trim())
    .filter(Boolean)
    .slice(0, 6)
}

function buildExtraPrompt() {
  return extraPrompt.value.trim()
}

function formatPageNo(pageNo?: number) {
  return String(pageNo || 0).padStart(2, "0")
}

function shortProgressLabel(message?: string) {
  if (!message) return ""
  if (message.includes("读取") || message.includes("等待")) return "准备中"
  if (message.includes("页面") || message.includes("内容")) return "生成内容"
  if (message.includes("优化") || message.includes("教学设计")) return "优化设计"
  if (message.includes("图片") || message.includes("检索")) return "匹配图片"
  if (message.includes("完成")) return "生成完成"
  if (message.includes("失败")) return "生成失败"
  return message.length > 4 ? message.slice(0, 4) : message
}

function resourceTypeName(type: string) {
  const names: Record<string, string> = {
    IMG: "图片", VIDEO: "视频", SONG: "音频", MUSIC: "乐谱", LISTEN: "听音练习",
    RHYTHM: "节奏练习", THEORY: "乐理知识", MUSIC_WIKI: "名曲鉴赏", INSTRUMENT: "乐器百科", MUSICIAN: "音乐家",
  }
  return names[type] || "课堂资源"
}

</script>

<style lang="scss" scoped>
.ai-dialog {
  height: 82vh;
  display: flex;
  flex-direction: column;
  color: #1f2933;
}
.header,
.footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.title {
  font-size: 24px;
  font-weight: 700;
  color: #1f2933;
}
.sub {
  margin-top: 6px;
  color: #7b8794;
  font-size: 14px;
}
.progress-strip,
.loading-strip {
  margin-top: 12px;
  height: 42px;
  display: flex;
  align-items: center;
  gap: 12px;
}
.loading-strip {
  color: #52616b;
  font-size: 13px;
}
.loading-dot {
  width: 14px;
  height: 14px;
  border: 2px solid #d7e7ff;
  border-top-color: $themeColor;
  border-radius: 50%;
  animation: loading-rotate 0.8s linear infinite;
}
.current-step {
  width: 64px;
  flex-shrink: 0;
  color: $themeColor;
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
}
.progress-value {
  width: 42px;
  text-align: right;
  font-size: 13px;
  color: $themeColor;
  font-weight: 700;
}
.progress-line {
  height: 6px;
  flex: 1;
  overflow: hidden;
  border-radius: 999px;
  background: #e7edf5;
}
.progress-bar {
  height: 100%;
  border-radius: inherit;
  background: $themeColor;
  transition: width 0.25s ease;
}
@keyframes loading-rotate {
  to {
    transform: rotate(360deg);
  }
}
.extra {
  margin-top: 12px;
}
.label {
  margin-bottom: 8px;
  font-size: 14px;
  color: #52616b;
}
.outline {
  margin-top: 14px;
  min-height: 0;
  flex: 1;
  display: grid;
  grid-template-columns: 280px minmax(0, 1fr);
  gap: 14px;
}
.page-nav {
  overflow: auto;
  border: 1px solid #edf1f5;
  border-radius: 8px;
  background: #fafcff;
  padding: 8px;
}
.nav-item {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 42px;
  padding: 8px 10px;
  border: 0;
  border-radius: 6px;
  background: transparent;
  color: #52616b;
  text-align: left;
  cursor: pointer;
  &.active {
    background: #eaf4ff;
    color: #1f2933;
    .nav-no {
      color: #fff;
      background: $themeColor;
    }
  }
}
.nav-no {
  width: 34px;
  height: 28px;
  line-height: 28px;
  text-align: center;
  border-radius: 5px;
  color: #7b8794;
  background: #edf1f5;
  flex-shrink: 0;
  font-size: 12px;
  font-weight: 600;
}
.nav-title {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 13px;
  font-weight: 600;
}
.page-editor {
  min-width: 0;
  overflow: auto;
  border: 1px solid #edf1f5;
  border-radius: 8px;
  background: #fff;
  padding: 16px;
}
.editor-head {
  display: block;
}
.title-editor {
  max-width: 460px;
}
.purpose-card {
  margin-top: 12px;
}
.field-grid {
  margin-top: 12px;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 12px;
}
.field-card {
  padding: 12px;
  border: 1px solid #edf1f5;
  border-radius: 8px;
  background: #fbfcfe;
  &.visual {
    background: #fffaf3;
  }
}
.field-title {
  margin-bottom: 8px;
  color: #52616b;
  font-size: 13px;
  font-weight: 600;
}
.page-title,
.purpose-input,
.headline-input,
.page-bullets,
.page-design,
.keyword-input,
.remark-input {
  width: 100%;
  border: 1px solid #d9d9d9;
  border-radius: 6px;
  box-sizing: border-box;
  font-family: inherit;
}
.page-title {
  height: 36px;
  padding: 0 10px;
  font-size: 16px;
  font-weight: 600;
}
.purpose-input {
  height: 36px;
  padding: 0 10px;
  font-size: 14px;
}
.headline-input {
  height: 36px;
  padding: 0 10px;
  margin-bottom: 10px;
  font-size: 14px;
}
.page-bullets,
.page-design {
  height: 150px;
  padding: 10px;
  resize: vertical;
  line-height: 1.5;
}
.full-field {
  margin-top: 12px;
}
.page-design {
  height: 90px;
}
.resource-card {
  margin-top: 12px;
  padding: 10px 12px;
  border: 1px solid #dcefe9;
  border-radius: 6px;
  background: #f6fbf9;
}
.resource-head {
  display: flex;
  align-items: baseline;
  gap: 10px;
}
.resource-hint {
  color: #7b8794;
  font-size: 12px;
}
.resource-list {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.resource-item {
  display: flex;
  align-items: center;
  min-width: 0;
  height: 30px;
  padding: 0 10px;
  border: 1px solid #cfe6de;
  border-radius: 4px;
  background: #fff;
  font-size: 12px;
}
.resource-type {
  margin-right: 8px;
  color: #168f86;
  font-weight: 600;
}
.resource-name {
  max-width: 240px;
  overflow: hidden;
  color: #374151;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.keyword-card {
  margin-top: 12px;
}
.keyword-head {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin-bottom: 8px;
}
.keyword-label {
  color: #52616b;
  font-size: 13px;
  font-weight: 600;
}
.keyword-hint {
  color: #9aa5b1;
  font-size: 12px;
}
.keyword-input {
  height: 34px;
  padding: 0 10px;
}
.remark-card {
  margin-top: 12px;
  padding: 10px 12px;
  border-radius: 6px;
  background: #f7f9fc;
}
.remark-head {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin-bottom: 8px;
}
.remark-title {
  color: #52616b;
  font-size: 13px;
  font-weight: 600;
}
.remark-hint {
  color: #9aa5b1;
  font-size: 12px;
}
.remark-input {
  height: 72px;
  padding: 10px;
  resize: vertical;
  line-height: 1.5;
  background: #fff;
}
.empty {
  flex: 1;
  margin-top: 14px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px dashed #d9d9d9;
  color: #7b8794;
}
.task {
  min-height: 20px;
}
.footer {
  margin-top: 14px;
  justify-content: flex-end;
  gap: 10px;
}
</style>
