<script setup>
import { ref, computed, onUnmounted } from "vue";
import { useRouter } from "vue-router";
import axios from "axios";
import {
  DOUBAO_KEY,
  BAILIAN_API_KEY,
  QUESTION_EXPLANATION_ANALYSIS_URL,
  QUESTION_EXPLANATION_ANALYSIS_MODEL,
  QUESTION_EXPLANATION_ANALYSIS_TEMPERATURE,
  QUESTION_EXPLANATION_ANALYSIS_MAX_TOKENS,
  QUESTION_EXPLANATION_ANALYSIS_PROMPT,
  QUESTION_EXPLANATION_IMAGE_URL,
  QUESTION_EXPLANATION_IMAGE_MODEL,
  QUESTION_EXPLANATION_IMAGE_SIZE,
  QUESTION_EXPLANATION_IMAGE_STYLE,
  QUESTION_EXPLANATION_TTS_URL,
  QUESTION_EXPLANATION_TTS_MODEL,
  QUESTION_EXPLANATION_TTS_VOICE,
  QUESTION_EXPLANATION_TTS_LANGUAGE,
  QUESTION_EXPLANATION_TTS_FORMAT,
  QUESTION_EXPLANATION_TTS_SAMPLE_RATE,
  VIDEO_WIDTH,
  VIDEO_HEIGHT,
  VIDEO_FILENAME_PREFIX,
} from "@/config/index.js";
import {
  composeVideo,
  downloadVideo,
  createPreviewUrl,
  revokePreviewUrl,
} from "@/utils/videoComposer.js";

const router = useRouter();

// ── 生成 PNG 占位图（统一风格）──
function generatePlaceholderImage(title, width = 1920, height = 1080) {
  const canvas = document.createElement('canvas');
  canvas.width = width;
  canvas.height = height;
  const ctx = canvas.getContext('2d');
  
  // 创建深蓝色渐变背景（与统一风格一致）
  const gradient = ctx.createLinearGradient(0, 0, 0, height);
  gradient.addColorStop(0, '#1e293b');
  gradient.addColorStop(1, '#0f172a');
  ctx.fillStyle = gradient;
  ctx.fillRect(0, 0, width, height);
  
  // 添加柔和的光晕效果
  const glowGradient = ctx.createRadialGradient(width/2, height/2, 0, width/2, height/2, width/2);
  glowGradient.addColorStop(0, 'rgba(139, 92, 246, 0.1)');
  glowGradient.addColorStop(1, 'rgba(59, 130, 246, 0)');
  ctx.fillStyle = glowGradient;
  ctx.fillRect(0, 0, width, height);
  
  // 标题文字（白色，清晰易读）
  ctx.fillStyle = '#ffffff';
  ctx.font = 'bold 48px sans-serif';
  ctx.textAlign = 'center';
  ctx.textBaseline = 'middle';
  
  // 文字换行处理
  const maxWidth = width - 200;
  const words = title.split('');
  let line = '';
  const lines = [];
  
  for (let i = 0; i < words.length; i++) {
    const testLine = line + words[i];
    const metrics = ctx.measureText(testLine);
    if (metrics.width > maxWidth && line !== '') {
      lines.push(line);
      line = words[i];
    } else {
      line = testLine;
    }
  }
  lines.push(line);
  
  // 绘制多行文字
  const lineHeight = 60;
  const startY = height / 2 - (lines.length - 1) * lineHeight / 2;
  lines.forEach((l, i) => {
    ctx.fillText(l, width / 2, startY + i * lineHeight);
  });
  
  return canvas.toDataURL('image/png');
}

// ── 状态管理 ──
const status = ref("idle"); // idle | analyzing | generating | ready | playing | paused | completed | error
const questionText = ref("");
const errorMsg = ref("");

// ── 讲解内容数据 ──
const explanationData = ref(null); // 分析结果: { complexity, totalPoints, explanationPoints }
const slides = ref([]); // 每个slide: { order, title, explanationText, imagePrompt, imageUrl, audioUrl, audioLoaded, imageLoaded }
const currentSlideIndex = ref(0);
const audioPlayer = ref(null);

// ── 进度信息 ──
const progressInfo = ref({
  stage: "", // analyzing | generating_images | generating_audio
  current: 0,
  total: 0,
});

// ── 视频合成状态 ──
const videoStatus = ref("idle"); // idle | initializing | preparing | composing | merging | ready | error
const videoProgress = ref({
  stage: "",
  current: 0,
  total: 0,
  message: "",
});
const videoBlobUrl = ref(null);
const videoErrorMsg = ref("");

// ── 计算属性 ──
const currentSlide = computed(() => {
  if (slides.value.length === 0) return null;
  return slides.value[currentSlideIndex.value];
});

const progressPercent = computed(() => {
  if (progressInfo.value.total === 0) return 0;
  return Math.round((progressInfo.value.current / progressInfo.value.total) * 100);
});

const isPlaying = computed(() => status.value === "playing");
const isPaused = computed(() => status.value === "paused");

// ── API调用函数 ──

// 1. 分析试题并生成讲解点
async function analyzeQuestion() {
  try {
    status.value = "analyzing";
    progressInfo.value = { stage: "analyzing", current: 0, total: 1 };

    const response = await axios.post(
      QUESTION_EXPLANATION_ANALYSIS_URL,
      {
        model: QUESTION_EXPLANATION_ANALYSIS_MODEL,
        messages: [
          {
            role: "system",
            content: QUESTION_EXPLANATION_ANALYSIS_PROMPT,
          },
          {
            role: "user",
            content: questionText.value,
          },
        ],
        temperature: QUESTION_EXPLANATION_ANALYSIS_TEMPERATURE,
        max_tokens: QUESTION_EXPLANATION_ANALYSIS_MAX_TOKENS,
      },
      {
        headers: {
          Authorization: `Bearer ${DOUBAO_KEY}`,
          "Content-Type": "application/json",
        },
      }
    );

    const content = response.data.choices[0].message.content;
    
    // 解析JSON响应 - 多种尝试方式
    let jsonData = null;
    let parseError = null;
    
    // 方法1: 尝试提取完整的JSON对象（包括嵌套的花括号）
    try {
      // 找到第一个 { 和最后一个 }
      const startIndex = content.indexOf('{');
      const lastIndex = content.lastIndexOf('}');
      
      if (startIndex === -1 || lastIndex === -1) {
        throw new Error("未找到JSON对象标记");
      }
      
      let jsonStr = content.substring(startIndex, lastIndex + 1);
      
      // 清理可能的问题字符（控制字符、多余的空白等）
      jsonStr = jsonStr
        .replace(/[\x00-\x1F\x7F]/g, '') // 移除控制字符
        .replace(/\n/g, '\\n') // 转义换行符
        .replace(/\r/g, '\\r') // 转义回车符
        .replace(/\t/g, '\\t'); // 转义制表符
      
      jsonData = JSON.parse(jsonStr);
    } catch (e) {
      parseError = e;
      console.warn("方法1解析失败:", e.message);
      
      // 方法2: 尝试使用正则提取并修复常见问题
      try {
        const jsonMatch = content.match(/\{[\s\S]*\}/);
        if (jsonMatch) {
          let jsonStr = jsonMatch[0];
          
          // 修复常见问题：未转义的引号
          // 在字符串值内部的双引号前添加转义符
          jsonStr = jsonStr.replace(/"([^"]*)"([^":]*)"([^"]*)":/g, '"$1\\"$2\\"$3":');
          
          jsonData = JSON.parse(jsonStr);
          parseError = null;
        }
      } catch (e2) {
        console.warn("方法2解析失败:", e2.message);
      }
    }
    
    if (!jsonData) {
      console.error("AI返回内容:", content);
      console.error("解析错误详情:", parseError);
      throw new Error(`无法解析试题分析结果。${parseError ? parseError.message : '请检查返回格式'}`);
    }

    explanationData.value = jsonData;
    progressInfo.value.current = 1;

    // 初始化slides数组
    slides.value = explanationData.value.explanationPoints.map((point) => ({
      ...point,
      imageUrl: null,
      audioUrl: null,
      audioLoaded: false,
      imageLoaded: false,
    }));

    return true;
  } catch (error) {
    console.error("分析试题失败:", error);
    errorMsg.value = `试题分析失败: ${error.response?.data?.error?.message || error.message}`;
    status.value = "error";
    return false;
  }
}

// 2. 批量生成图片（串行，避免超时）
async function generateImages() {
  try {
    progressInfo.value = {
      stage: "generating_images",
      current: 0,
      total: slides.value.length,
    };

    // 串行生成图片，避免并发超时
    for (let index = 0; index < slides.value.length; index++) {
      const slide = slides.value[index];
      
      // 如果不是第一个请求，等待 1 秒
      if (index > 0) {
        await new Promise(resolve => setTimeout(resolve, 1000));
      }
      
      try {
        const response = await axios.post(
          QUESTION_EXPLANATION_IMAGE_URL,
          {
            model: QUESTION_EXPLANATION_IMAGE_MODEL,
            input: {
              messages: [
                {
                  role: "user",
                  content: [
                    {
                      text: `原题：${questionText.value}\n\n讲解内容：${slide.explanationText}\n\n${QUESTION_EXPLANATION_IMAGE_STYLE}\n\n请为以上讲解生成配套的教学图示。要求：严格围绕原题内容，视觉化呈现讲解的核心要点，清晰、直观、适合教学展示。`
                    }
                  ]
                }
              ]
            },
            parameters: {
              size: QUESTION_EXPLANATION_IMAGE_SIZE,
              watermark: false,
              prompt_extend: true,
              negative_prompt: "低分辨率，低画质，模糊，不清晰，过于复杂的细节，不适合教学的内容"
            }
          },
          {
            headers: {
              Authorization: `Bearer ${BAILIAN_API_KEY}`,
              "Content-Type": "application/json",
            },
            timeout: 60000, // 60秒超时
          }
        );

        // 提取图片URL（阿里云 qwen-image 返回格式）
        let imageUrl = response.data.output?.choices?.[0]?.message?.content?.[0]?.image;
        if (imageUrl) {
          // 保存原始完整URL（用于后端下载）
          slide.originalImageUrl = imageUrl;
          // 通过代理转发，解决COEP策略问题（前端显示用）
          if (imageUrl.includes('oss-') && imageUrl.includes('aliyuncs.com')) {
            // 匹配任意阿里云OSS域名
            slide.imageUrl = imageUrl.replace(/https?:\/\/[^\/]+\.oss[^\/]*\.aliyuncs\.com/, '/oss-image');
          } else {
            slide.imageUrl = imageUrl;
          }
        } else {
          // API 返回格式异常，使用 PNG 占位图
          console.warn(`第${index + 1}张图片返回格式异常，使用占位图`);
          const placeholderUrl = generatePlaceholderImage(slide.title);
          slide.imageUrl = placeholderUrl;
          slide.originalImageUrl = placeholderUrl;
        }
        slide.imageLoaded = true;
        progressInfo.value.current++;
      } catch (error) {
        console.error(`生成第${index + 1}张图片失败:`, error);
        
        // 如果是限流错误，等待后重试
        if (error.response?.data?.code === "Throttling.RateQuota" || 
            error.response?.status === 429) {
          console.log(`第${index + 1}张图片限流，等待 3 秒后重试...`);
          await new Promise(resolve => setTimeout(resolve, 3000));
          
          try {
            const retryResponse = await axios.post(
              QUESTION_EXPLANATION_IMAGE_URL,
              {
                model: QUESTION_EXPLANATION_IMAGE_MODEL,
                input: {
                  messages: [
                    {
                      role: "user",
                      content: [
                        {
                          text: `原题：${questionText.value}\n\n讲解内容：${slide.explanationText}\n\n${QUESTION_EXPLANATION_IMAGE_STYLE}\n\n请为以上讲解生成配套的教学图示。要求：严格围绕原题内容，视觉化呈现讲解的核心要点，清晰、直观、适合教学展示。`
                        }
                      ]
                    }
                  ]
                },
                parameters: {
                  size: QUESTION_EXPLANATION_IMAGE_SIZE,
                  watermark: false,
                  prompt_extend: true,
                  negative_prompt: "低分辨率，低画质，模糊，不清晰，过于复杂的细节，不适合教学的内容"
                }
              },
              {
                headers: {
                  Authorization: `Bearer ${BAILIAN_API_KEY}`,
                  "Content-Type": "application/json",
                },
                timeout: 60000,
              }
            );
            
            let imageUrl = retryResponse.data.output?.choices?.[0]?.message?.content?.[0]?.image;
            if (imageUrl) {
              // 保存原始完整URL（用于后端下载）
              slide.originalImageUrl = imageUrl;
              // 代理路径（前端显示用）
              if (imageUrl.includes('oss-') && imageUrl.includes('aliyuncs.com')) {
                slide.imageUrl = imageUrl.replace(/https?:\/\/[^\/]+\.oss[^\/]*\.aliyuncs\.com/, '/oss-image');
              } else {
                slide.imageUrl = imageUrl;
              }
            } else {
              console.warn(`第${index + 1}张图片重试返回格式异常，使用占位图`);
              // 使用统一风格的占位图
              const placeholderUrl = generatePlaceholderImage(slide.title);
              slide.imageUrl = placeholderUrl;
              slide.originalImageUrl = placeholderUrl;
            }
            slide.imageLoaded = true;
            progressInfo.value.current++;
          } catch (retryError) {
            console.error(`第${index + 1}张图片重试失败:`, retryError);
            // 重试失败使用占位图
            const placeholderUrl = generatePlaceholderImage(slide.title);
            slide.imageUrl = placeholderUrl;
            slide.originalImageUrl = placeholderUrl;
            slide.imageLoaded = true;
            progressInfo.value.current++;
          }
        } else {
          // 其他错误使用占位图
          const placeholderUrl = generatePlaceholderImage(slide.title);
          slide.imageUrl = placeholderUrl;
          slide.originalImageUrl = placeholderUrl;
          slide.imageLoaded = true;
          progressInfo.value.current++;
        }
      }
    }

    return true;
  } catch (error) {
    console.error("生成图片失败:", error);
    // 图片生成失败不影响后续流程，使用本地占位图
    slides.value.forEach((slide) => {
      if (!slide.imageLoaded) {
        const placeholderUrl = generatePlaceholderImage(slide.title);
        slide.imageUrl = placeholderUrl;
        slide.originalImageUrl = placeholderUrl;
        slide.imageLoaded = true;
      }
    });
    return true;
  }
}

// 3. 批量生成音频（串行，避免限流）
async function generateAudio() {
  try {
    progressInfo.value = {
      stage: "generating_audio",
      current: 0,
      total: slides.value.length,
    };

    // 串行生成音频，每个请求间隔 1 秒，避免限流
    for (let index = 0; index < slides.value.length; index++) {
      const slide = slides.value[index];
      
      // 如果不是第一个请求，等待 1 秒
      if (index > 0) {
        await new Promise(resolve => setTimeout(resolve, 1000));
      }
      
      try {
        const response = await axios.post(
          QUESTION_EXPLANATION_TTS_URL,
          {
            model: QUESTION_EXPLANATION_TTS_MODEL,
            input: {
              text: slide.explanationText,
            },
            parameters: {
              voice: QUESTION_EXPLANATION_TTS_VOICE,
              language_type: QUESTION_EXPLANATION_TTS_LANGUAGE,
              format: QUESTION_EXPLANATION_TTS_FORMAT,
              sample_rate: QUESTION_EXPLANATION_TTS_SAMPLE_RATE,
            },
          },
          {
            headers: {
              Authorization: `Bearer ${BAILIAN_API_KEY}`,
              "Content-Type": "application/json",
            },
            timeout: 30000, // 30秒超时
          }
        );

        // 提取音频URL（阿里云TTS返回格式）
        let audioUrl = response.data.output?.audio_url || response.data.output?.audio?.url;
        if (audioUrl) {
          // 保存原始完整URL（用于后端下载）
          slide.originalAudioUrl = audioUrl;
          // 通过代理转发，解决COEP策略问题（前端播放用）
          if (audioUrl.includes('oss-') && audioUrl.includes('aliyuncs.com')) {
            // 匹配任意阿里云OSS域名
            slide.audioUrl = audioUrl.replace(/https?:\/\/[^\/]+\.oss[^\/]*\.aliyuncs\.com/, '/oss-audio');
          } else {
            slide.audioUrl = audioUrl;
          }
          slide.audioLoaded = true;
          progressInfo.value.current++;
        } else {
          // API 返回格式异常，记录错误但不中断流程
          console.warn(`第${index + 1}个音频返回格式异常`);
        }
      } catch (error) {
        console.error(`生成第${index + 1}个音频失败:`, error);
        
        // 如果是限流错误，等待更长时间后重试一次
        if (error.response?.data?.code === "Throttling.RateQuota") {
          console.log(`第${index + 1}个音频限流，等待 3 秒后重试...`);
          await new Promise(resolve => setTimeout(resolve, 3000));
          
          try {
            const retryResponse = await axios.post(
              QUESTION_EXPLANATION_TTS_URL,
              {
                model: QUESTION_EXPLANATION_TTS_MODEL,
                input: {
                  text: slide.explanationText,
                },
                parameters: {
                  voice: QUESTION_EXPLANATION_TTS_VOICE,
                  language_type: QUESTION_EXPLANATION_TTS_LANGUAGE,
                  format: QUESTION_EXPLANATION_TTS_FORMAT,
                  sample_rate: QUESTION_EXPLANATION_TTS_SAMPLE_RATE,
                },
              },
              {
                headers: {
                  Authorization: `Bearer ${BAILIAN_API_KEY}`,
                  "Content-Type": "application/json",
                },
                timeout: 30000,
              }
            );
            
            let audioUrl = retryResponse.data.output?.audio_url || retryResponse.data.output?.audio?.url;
            if (audioUrl) {
              // 保存原始完整URL（用于后端下载）
              slide.originalAudioUrl = audioUrl;
              // 代理路径（前端播放用）
              if (audioUrl.includes('oss-') && audioUrl.includes('aliyuncs.com')) {
                slide.audioUrl = audioUrl.replace(/https?:\/\/[^\/]+\.oss[^\/]*\.aliyuncs\.com/, '/oss-audio');
              } else {
                slide.audioUrl = audioUrl;
              }
              slide.audioLoaded = true;
              progressInfo.value.current++;
            } else {
              console.warn(`第${index + 1}个音频重试返回格式异常`);
            }
          } catch (retryError) {
            console.error(`第${index + 1}个音频重试失败:`, retryError);
            // 重试失败不影响其他音频
          }
        }
      }
    }
    
    // 检查是否至少有一个音频生成成功
    const successCount = slides.value.filter(s => s.audioLoaded).length;
    if (successCount === 0) {
      throw new Error("所有音频生成失败");
    }

    return true;
  } catch (error) {
    console.error("生成音频失败:", error);
    errorMsg.value = `音频生成失败: ${error.message}`;
    status.value = "error";
    return false;
  }
}

// ── 主流程：生成讲解内容 ──
async function generateExplanation() {
  if (!questionText.value.trim()) {
    errorMsg.value = "请输入试题内容";
    return;
  }

  errorMsg.value = "";
  status.value = "analyzing";

  // 步骤1: 分析试题
  const analysisSuccess = await analyzeQuestion();
  if (!analysisSuccess) return;

  // 步骤2和3: 并发生成图片和音频
  status.value = "generating";
  const [, audioSuccess] = await Promise.all([
    generateImages(),
    generateAudio(),
  ]);

  if (!audioSuccess) return;

  // 准备完成，进入播放状态
  status.value = "ready";
  currentSlideIndex.value = 0;
}

// ── 播放控制 ──

function initAudioPlayer() {
  if (!audioPlayer.value) {
    audioPlayer.value = new Audio();
    audioPlayer.value.addEventListener("ended", handleAudioEnded);
    audioPlayer.value.addEventListener("error", handleAudioError);
  }
}

function handleAudioEnded() {
  // 当前音频播放完毕，自动切换下一张
  if (currentSlideIndex.value < slides.value.length - 1) {
    nextSlide();
  } else {
    // 播放完成
    status.value = "completed";
  }
}

function handleAudioError(error) {
  console.error("音频播放错误:", error);
  // 音频错误时也尝试切换到下一张
  handleAudioEnded();
}

function playCurrentSlide() {
  const slide = currentSlide.value;
  if (!slide || !slide.audioUrl) {
    // 如果当前slide没有音频，直接切换下一张
    handleAudioEnded();
    return;
  }

  initAudioPlayer();
  audioPlayer.value.src = slide.audioUrl;
  audioPlayer.value.play().catch((error) => {
    console.error("播放失败:", error);
    handleAudioEnded();
  });
  status.value = "playing";
}

function startPlayback() {
  if (slides.value.length === 0) return;
  currentSlideIndex.value = 0;
  playCurrentSlide();
}

function pausePlayback() {
  if (audioPlayer.value) {
    audioPlayer.value.pause();
  }
  status.value = "paused";
}

function resumePlayback() {
  if (audioPlayer.value) {
    audioPlayer.value.play();
  }
  status.value = "playing";
}

function nextSlide() {
  if (currentSlideIndex.value < slides.value.length - 1) {
    currentSlideIndex.value++;
    if (isPlaying.value || status.value === "ready") {
      playCurrentSlide();
    }
  }
}

function prevSlide() {
  if (currentSlideIndex.value > 0) {
    currentSlideIndex.value--;
    if (isPlaying.value) {
      playCurrentSlide();
    }
  }
}

function restartPlayback() {
  if (audioPlayer.value) {
    audioPlayer.value.pause();
  }
  status.value = "ready";
  currentSlideIndex.value = 0;
}

function resetAll() {
  if (audioPlayer.value) {
    audioPlayer.value.pause();
    audioPlayer.value = null;
  }
  questionText.value = "";
  explanationData.value = null;
  slides.value = [];
  currentSlideIndex.value = 0;
  errorMsg.value = "";
  status.value = "idle";
  // 重置视频状态
  resetVideoState();
}

// ── 生命周期 ──
onUnmounted(() => {
  if (audioPlayer.value) {
    audioPlayer.value.pause();
    audioPlayer.value.removeEventListener("ended", handleAudioEnded);
    audioPlayer.value.removeEventListener("error", handleAudioError);
  }
});

// 返回首页
function goHome() {
  router.push("/");
}

// ── 视频合成功能 ──

/**
 * 开始合成视频
 */
async function startComposeVideo() {
  if (slides.value.length === 0) {
    videoErrorMsg.value = "没有可用的讲解内容";
    return;
  }

  // 检查是否有完整的图片和音频
  const validSlides = slides.value.filter(s => s.imageUrl && s.audioUrl);
  if (validSlides.length === 0) {
    videoErrorMsg.value = "请先生成图片和音频";
    return;
  }

  videoErrorMsg.value = "";
  videoStatus.value = "preparing";
  videoProgress.value = {
    stage: "preparing",
    current: 0,
    total: validSlides.length,
    message: "正在准备视频合成...",
  };

  try {
    const blob = await composeVideo(
      validSlides,
      {
        width: VIDEO_WIDTH,
        height: VIDEO_HEIGHT,
      },
      (progress) => {
        videoProgress.value = progress;
        // 更新状态以匹配进度阶段
        if (progress.stage === 'preparing') {
          videoStatus.value = 'preparing';
        } else if (progress.stage === 'composing') {
          videoStatus.value = 'composing';
        } else if (progress.stage === 'merging') {
          videoStatus.value = 'merging';
        } else if (progress.stage === 'completed') {
          videoStatus.value = 'ready';
        }
      }
    );

    // 创建预览URL
    if (videoBlobUrl.value) {
      revokePreviewUrl(videoBlobUrl.value);
    }
    videoBlobUrl.value = createPreviewUrl(blob);
    videoStatus.value = "ready";
    videoProgress.value = {
      stage: "completed",
      current: 1,
      total: 1,
      message: "视频合成完成！",
    };

  } catch (error) {
    console.error("视频合成失败:", error);
    videoErrorMsg.value = `视频合成失败: ${error.message}`;
    videoStatus.value = "error";
  }
}

/**
 * 下载视频
 */
function handleDownloadVideo() {
  if (!videoBlobUrl.value) return;
  
  // 从 Blob URL 获取 Blob
  fetch(videoBlobUrl.value)
    .then(res => res.blob())
    .then(blob => {
      const timestamp = new Date().toISOString().slice(0, 10);
      const filename = `${VIDEO_FILENAME_PREFIX}${timestamp}.mp4`;
      downloadVideo(blob, filename);
    })
    .catch(err => {
      console.error("下载失败:", err);
      videoErrorMsg.value = "下载失败，请重试";
    });
}

/**
 * 重置视频合成状态
 */
function resetVideoState() {
  if (videoBlobUrl.value) {
    revokePreviewUrl(videoBlobUrl.value);
  }
  videoStatus.value = "idle";
  videoProgress.value = { stage: "", current: 0, total: 0, message: "" };
  videoBlobUrl.value = null;
  videoErrorMsg.value = "";
}
</script>

<template>
  <div class="question-explanation-page">
    <!-- 背景装饰 -->
    <div class="bg-decoration"></div>

    <!-- 主内容区 -->
    <div class="main-content">
      <!-- 顶部导航栏 -->
      <header class="top-nav">
        <button @click="goHome" class="back-button">
          <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="icon-sm">
            <path stroke-linecap="round" stroke-linejoin="round" d="M15.75 19.5L8.25 12l7.5-7.5" />
          </svg>
          <span>返回首页</span>
        </button>
        <h1 class="page-title">AI试题讲解生成</h1>
        <div class="spacer"></div>
      </header>

      <!-- 内容区域 -->
      <main class="content-area">
        <!-- 输入区域（idle状态） -->
        <div v-if="status === 'idle'" class="input-section">
          <div class="input-card">
            <div class="input-header">
              <h2 class="input-title">输入试题内容</h2>
              <p class="input-desc">支持文字输入，系统将自动分析试题并生成图文讲解</p>
            </div>

            <textarea
              v-model="questionText"
              placeholder="请输入试题内容..."
              class="question-textarea"
            ></textarea>

            <div v-if="errorMsg" class="error-message">
              <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="icon-sm">
                <path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m9-.75a9 9 0 11-18 0 9 9 0 0118 0zm-9 3.75h.008v.008H12v-.008z" />
              </svg>
              <span>{{ errorMsg }}</span>
            </div>

            <button
              @click="generateExplanation"
              :disabled="!questionText.trim()"
              class="generate-button"
            >
              开始生成讲解
            </button>
          </div>
        </div>

        <!-- 加载状态 -->
        <div v-else-if="status === 'analyzing' || status === 'generating'" class="loading-section">
          <div class="loading-content">
            <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="loading-icon">
              <path stroke-linecap="round" stroke-linejoin="round" d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0l3.181 3.183a8.25 8.25 0 0013.803-3.7M4.031 9.865a8.25 8.25 0 0113.803-3.7l3.181 3.182m0-4.991v4.99" />
            </svg>
            <h2 class="loading-title">
              {{ status === 'analyzing' ? '正在分析试题...' : '正在生成资源...' }}
            </h2>
            <p class="loading-desc">
              {{ progressInfo.stage === 'analyzing' ? '分析试题复杂度，拆分讲解点' : 
                 progressInfo.stage === 'generating_images' ? `正在生成讲解图片 (${progressInfo.current}/${progressInfo.total})` :
                 `正在合成讲解音频 (${progressInfo.current}/${progressInfo.total})` }}
            </p>
            <div class="progress-bar">
              <div 
                class="progress-fill"
                :style="{ width: progressPercent + '%' }"
              ></div>
            </div>
          </div>
        </div>

        <!-- 错误状态 -->
        <div v-else-if="status === 'error'" class="error-section">
          <div class="error-content">
            <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="error-icon">
              <path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m9-.75a9 9 0 11-18 0 9 9 0 0118 0zm-9 3.75h.008v.008H12v-.008z" />
            </svg>
            <h2 class="error-title">生成失败</h2>
            <p class="error-desc">{{ errorMsg }}</p>
            <button @click="resetAll" class="retry-button">
              重新开始
            </button>
          </div>
        </div>

        <!-- 播放器界面 -->
        <div v-else class="player-section">
          <!-- 幻灯片展示区 -->
          <div class="slideshow-area">
            <div v-if="currentSlide" class="slideshow-container">
              <!-- 图片展示 -->
              <div class="slide-image-wrapper">
                <img
                  v-if="currentSlide.imageUrl"
                  :src="currentSlide.imageUrl"
                  :alt="currentSlide.title"
                  class="slide-image"
                />
                <div v-else class="image-placeholder">
                  <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="placeholder-icon">
                    <path stroke-linecap="round" stroke-linejoin="round" d="M2.25 15.75l5.159-5.159a2.25 2.25 0 013.182 0l5.159 5.159m-1.5-1.5l1.409-1.409a2.25 2.25 0 013.182 0l2.909 2.909m-18 3.75h16.5a1.5 1.5 0 001.5-1.5V6a1.5 1.5 0 00-1.5-1.5H3.75A1.5 1.5 0 002.25 6v12a1.5 1.5 0 001.5 1.5zm10.5-11.25h.008v.008h-.008V8.25zm.375 0a.375.375 0 11-.75 0 .375.375 0 01.75 0z" />
                  </svg>
                </div>
                
                <!-- 图片标题覆盖层 -->
                <div class="slide-title-overlay">
                  <h3 class="slide-title">{{ currentSlide.title }}</h3>
                </div>
              </div>

              <!-- 讲解文本 -->
              <div class="explanation-text-card">
                <div class="explanation-text-wrapper">
                  <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="volume-icon">
                    <path stroke-linecap="round" stroke-linejoin="round" d="M19.114 5.636a9 9 0 010 12.728M16.463 8.288a5.25 5.25 0 010 7.424M6.75 8.25l4.72-4.72a.75.75 0 011.28.53v15.88a.75.75 0 01-1.28.53l-4.72-4.72H4.51c-.88 0-1.704-.507-1.938-1.354A9.01 9.01 0 012.25 12c0-.83.112-1.633.322-2.396C2.806 8.756 3.63 8.25 4.51 8.25H6.75z" />
                  </svg>
                  <p class="explanation-text">{{ currentSlide.explanationText }}</p>
                </div>
              </div>
            </div>
          </div>

          <!-- 播放控制区 -->
          <div class="player-controls">
            <div class="controls-container">
              <!-- 进度指示器 -->
              <div class="progress-indicator">
                <span class="progress-text">{{ currentSlideIndex + 1 }} / {{ slides.length }}</span>
                <div class="total-progress-bar">
                  <div
                    class="total-progress-fill"
                    :style="{ width: ((currentSlideIndex + 1) / slides.length * 100) + '%' }"
                  ></div>
                </div>
              </div>

              <!-- 控制按钮 -->
              <div class="control-buttons">
                <button
                  @click="prevSlide"
                  :disabled="currentSlideIndex === 0"
                  class="control-button secondary"
                >
                  <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="icon-md">
                    <path stroke-linecap="round" stroke-linejoin="round" d="M15.75 19.5L8.25 12l7.5-7.5" />
                  </svg>
                </button>

                <!-- 播放/暂停按钮 -->
                <button
                  v-if="status === 'ready' || status === 'completed'"
                  @click="startPlayback"
                  class="control-button primary"
                >
                  <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="icon-lg">
                    <path stroke-linecap="round" stroke-linejoin="round" d="M5.25 5.653c0-.856.917-1.398 1.667-.986l11.54 6.348a1.125 1.125 0 010 1.971l-11.54 6.347a1.125 1.125 0 01-1.667-.985V5.653z" />
                  </svg>
                </button>
                <button
                  v-else-if="isPlaying"
                  @click="pausePlayback"
                  class="control-button primary"
                >
                  <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="icon-lg">
                    <path stroke-linecap="round" stroke-linejoin="round" d="M15.75 5.25v13.5m-7.5-13.5v13.5" />
                  </svg>
                </button>
                <button
                  v-else-if="isPaused"
                  @click="resumePlayback"
                  class="control-button primary"
                >
                  <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="icon-lg">
                    <path stroke-linecap="round" stroke-linejoin="round" d="M5.25 5.653c0-.856.917-1.398 1.667-.986l11.54 6.348a1.125 1.125 0 010 1.971l-11.54 6.347a1.125 1.125 0 01-1.667-.985V5.653z" />
                  </svg>
                </button>

                <button
                  @click="nextSlide"
                  :disabled="currentSlideIndex === slides.length - 1"
                  class="control-button secondary"
                >
                  <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="icon-md">
                    <path stroke-linecap="round" stroke-linejoin="round" d="M8.25 4.5l7.5 7.5-7.5 7.5" />
                  </svg>
                </button>

                <button
                  @click="restartPlayback"
                  class="control-button secondary"
                  title="重新播放"
                >
                  <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="icon-md">
                    <path stroke-linecap="round" stroke-linejoin="round" d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0l3.181 3.183a8.25 8.25 0 0013.803-3.7M4.031 9.865a8.25 8.25 0 0113.803-3.7l3.181 3.182m0-4.991v4.99" />
                  </svg>
                </button>

                <button
                  @click="resetAll"
                  class="control-button secondary"
                  title="返回输入"
                >
                  重新输入
                </button>
              </div>

              <!-- 播放完成提示 -->
              <div v-if="status === 'completed'" class="completion-message">
                <p class="completion-text">🎉 讲解播放完成！</p>
                <button @click="resetAll" class="new-generation-button">
                  生成新的讲解
                </button>
              </div>

              <!-- 视频合成区域 -->
              <div v-if="status === 'ready' || status === 'completed' || videoStatus !== 'idle'" class="video-compose-section">
                <div class="compose-header">
                  <h4 class="compose-title">
                    <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="icon-md">
                      <path stroke-linecap="round" stroke-linejoin="round" d="M15.75 10.5l4.72-4.72a.75.75 0 011.28.53v11.38a.75.75 0 01-1.28.53l-4.72-4.72M4.5 18.75h9a2.25 2.25 0 002.25-2.25v-9a2.25 2.25 0 00-2.25-2.25h-9A2.25 2.25 0 002.25 7.5v9a2.25 2.25 0 002.25 2.25z" />
                    </svg>
                    视频合成
                  </h4>
                </div>

                <!-- 合成按钮（未开始时显示） -->
                <div v-if="videoStatus === 'idle'" class="compose-actions">
                  <button @click="startComposeVideo" class="compose-button">
                    <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="icon-sm">
                      <path stroke-linecap="round" stroke-linejoin="round" d="M3.375 19.5h17.25m-17.25 0a1.125 1.125 0 01-1.125-1.125M3.375 19.5h7.5c.621 0 1.125-.504 1.125-1.125m-9.75 0V5.625m0 12.75v-1.5c0-.621.504-1.125 1.125-1.125m18.375 2.625V5.625m0 12.75v-1.5c0-.621-.504-1.125-1.125-1.125M3.375 5.625c0-.621.504-1.125 1.125-1.125h5.25c.621 0 1.125.504 1.125 1.125v1.5c0 .621-.504 1.125-1.125 1.125h-5.25a1.125 1.125 0 01-1.125-1.125v-1.5zM3.375 5.625v-1.5c0-.621.504-1.125 1.125-1.125h5.25c.621 0 1.125.504 1.125 1.125m-6.375 0a1.125 1.125 0 011.125-1.125h5.25c.621 0 1.125.504 1.125 1.125m0 0v1.5c0 .621-.504 1.125-1.125 1.125m0-2.625c0-.621.504-1.125 1.125-1.125h5.25c.621 0 1.125.504 1.125 1.125v1.5c0 .621-.504 1.125-1.125 1.125h-5.25a1.125 1.125 0 01-1.125-1.125v-1.5z" />
                    </svg>
                    生成视频文件
                  </button>
                  <p class="compose-hint">将所有讲解合成为一个完整的视频文件，支持下载到本地</p>
                </div>

                <!-- 合成进度 -->
                <div v-else-if="videoStatus === 'initializing' || videoStatus === 'preparing' || videoStatus === 'composing' || videoStatus === 'merging'" class="compose-progress">
                  <div class="progress-icon-wrapper">
                    <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="progress-icon spinning">
                      <path stroke-linecap="round" stroke-linejoin="round" d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0l3.181 3.183a8.25 8.25 0 0013.803-3.7M4.031 9.865a8.25 8.25 0 0113.803-3.7l3.181 3.182m0-4.991v4.99" />
                    </svg>
                  </div>
                  <p class="progress-stage-text">{{ videoProgress.message }}</p>
                  <div class="video-progress-bar">
                    <div 
                      class="video-progress-fill"
                      :style="{ width: (videoProgress.current / videoProgress.total * 100) + '%' }"
                    ></div>
                  </div>
                  <p class="progress-detail">{{ videoProgress.current }} / {{ videoProgress.total }}</p>
                </div>

                <!-- 合成完成 - 视频预览 -->
                <div v-else-if="videoStatus === 'ready'" class="video-ready-section">
                  <div class="video-preview-wrapper">
                    <video 
                      :src="videoBlobUrl" 
                      controls 
                      class="video-player"
                      controlslist="nodownload"
                    ></video>
                  </div>
                  <div class="video-actions">
                    <button @click="handleDownloadVideo" class="download-video-button">
                      <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="icon-sm">
                        <path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5M16.5 12L12 16.5m0 0L7.5 12m4.5 4.5V3" />
                      </svg>
                      下载视频
                    </button>
                    <button @click="resetVideoState" class="reset-compose-button">
                      重新生成
                    </button>
                  </div>
                </div>

                <!-- 合成错误 -->
                <div v-else-if="videoStatus === 'error'" class="compose-error">
                  <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="error-icon-sm">
                    <path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m9-.75a9 9 0 11-18 0 9 9 0 0118 0zm-9 3.75h.008v.008H12v-.008z" />
                  </svg>
                  <p class="error-text">{{ videoErrorMsg }}</p>
                  <button @click="startComposeVideo" class="retry-compose-button">
                    重试
                  </button>
                </div>
              </div>
            </div>
          </div>
        </div>
      </main>
    </div>
  </div>
</template>

<style scoped>
/* ── 页面基础样式 ── */
.question-explanation-page {
  min-height: 100vh;
  background-color: #0f172a;
  color: #ffffff;
  overflow: hidden;
  position: relative;
}

/* ── 背景装饰 ── */
.bg-decoration {
  position: fixed;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
}

.bg-decoration::before {
  content: '';
  position: absolute;
  top: 25%;
  left: 25%;
  width: 24rem;
  height: 24rem;
  background: rgba(139, 92, 246, 0.1);
  border-radius: 50%;
  filter: blur(80px);
}

.bg-decoration::after {
  content: '';
  position: absolute;
  bottom: 25%;
  right: 25%;
  width: 24rem;
  height: 24rem;
  background: rgba(59, 130, 246, 0.1);
  border-radius: 50%;
  filter: blur(80px);
}

/* ── 主内容区 ── */
.main-content {
  position: relative;
  z-index: 10;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

/* ── 顶部导航栏 ── */
.top-nav {
  padding: 1rem 1.5rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}

.back-button {
  color: rgba(255, 255, 255, 0.6);
  background: none;
  border: none;
  cursor: pointer;
  transition: color 0.3s;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 1rem;
  padding: 0;
}

.back-button:hover {
  color: #ffffff;
}

.page-title {
  font-size: 1.25rem;
  font-weight: 600;
  margin: 0;
}

.spacer {
  width: 5rem;
}

/* ── 内容区域 ── */
.content-area {
  flex: 1;
  padding: 1.5rem;
  display: flex;
  flex-direction: column;
}

/* ── 输入区域 ── */
.input-section {
  max-width: 48rem;
  margin: 0 auto;
  width: 100%;
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.input-card {
  background: rgba(255, 255, 255, 0.05);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 1.5rem;
  padding: 2rem;
}

.input-header {
  margin-bottom: 1.5rem;
}

.input-title {
  font-size: 1.5rem;
  font-weight: 600;
  margin: 0 0 0.5rem 0;
}

.input-desc {
  color: rgba(255, 255, 255, 0.6);
  font-size: 0.875rem;
  margin: 0;
}

.question-textarea {
  width: 100%;
  height: 16rem;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 1rem;
  padding: 1rem;
  color: #ffffff;
  font-size: 1rem;
  resize: none;
  outline: none;
  transition: border-color 0.3s;
  font-family: inherit;
  box-sizing: border-box;
}

.question-textarea::placeholder {
  color: rgba(255, 255, 255, 0.4);
}

.question-textarea:focus {
  border-color: rgba(139, 92, 246, 0.5);
}

.error-message {
  margin-top: 1rem;
  padding: 1rem;
  background: rgba(239, 68, 68, 0.1);
  border: 1px solid rgba(239, 68, 68, 0.2);
  border-radius: 0.75rem;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  color: #f87171;
}

.generate-button {
  margin-top: 1.5rem;
  width: 100%;
  padding: 1rem;
  background: linear-gradient(to right, #8b5cf6, #3b82f6);
  border: none;
  border-radius: 0.75rem;
  font-size: 1.125rem;
  font-weight: 600;
  color: #ffffff;
  cursor: pointer;
  transition: opacity 0.3s;
}

.generate-button:hover:not(:disabled) {
  opacity: 0.9;
}

.generate-button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* ── 加载状态 ── */
.loading-section {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
}

.loading-content {
  text-align: center;
}

.loading-icon {
  width: 4rem;
  height: 4rem;
  margin: 0 auto 1.5rem;
  animation: spin 1s linear infinite;
  color: #8b5cf6;
}

@keyframes spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

.loading-title {
  font-size: 1.5rem;
  font-weight: 600;
  margin: 0 0 0.5rem 0;
}

.loading-desc {
  color: rgba(255, 255, 255, 0.6);
  margin: 0 0 1rem 0;
}

.progress-bar {
  width: 16rem;
  height: 0.5rem;
  background: rgba(255, 255, 255, 0.1);
  border-radius: 9999px;
  overflow: hidden;
  margin: 0 auto;
}

.progress-fill {
  height: 100%;
  background: linear-gradient(to right, #8b5cf6, #3b82f6);
  transition: width 0.3s;
}

/* ── 错误状态 ── */
.error-section {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
}

.error-content {
  text-align: center;
  max-width: 28rem;
}

.error-icon {
  width: 4rem;
  height: 4rem;
  margin: 0 auto 1.5rem;
  color: #ef4444;
}

.error-title {
  font-size: 1.5rem;
  font-weight: 600;
  margin: 0 0 0.5rem 0;
}

.error-desc {
  color: rgba(255, 255, 255, 0.6);
  margin: 0 0 1.5rem 0;
}

.retry-button {
  padding: 0.75rem 2rem;
  background: linear-gradient(to right, #8b5cf6, #3b82f6);
  border: none;
  border-radius: 0.75rem;
  font-size: 1rem;
  font-weight: 600;
  color: #ffffff;
  cursor: pointer;
  transition: opacity 0.3s;
}

.retry-button:hover {
  opacity: 0.9;
}

/* ── 播放器界面 ── */
.player-section {
  flex: 1;
  display: flex;
  flex-direction: column;
}

.slideshow-area {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 1.5rem;
}

.slideshow-container {
  width: 100%;
  max-width: 64rem;
}

.slide-image-wrapper {
  position: relative;
  aspect-ratio: 16 / 9;
  background: rgba(255, 255, 255, 0.05);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 1.5rem;
  overflow: hidden;
  margin-bottom: 1rem;
}

.slide-image {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.image-placeholder {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.placeholder-icon {
  width: 6rem;
  height: 6rem;
  color: rgba(255, 255, 255, 0.2);
}

.slide-title-overlay {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.8), transparent);
  padding: 1.5rem;
}

.slide-title {
  font-size: 1.25rem;
  font-weight: 600;
  margin: 0;
}

.explanation-text-card {
  background: rgba(255, 255, 255, 0.05);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 1rem;
  padding: 1.5rem;
}

.explanation-text-wrapper {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
}

.volume-icon {
  width: 1.25rem;
  height: 1.25rem;
  color: #a78bfa;
  flex-shrink: 0;
  margin-top: 0.25rem;
}

.explanation-text {
  color: rgba(255, 255, 255, 0.9);
  line-height: 1.6;
  margin: 0;
}

/* ── 播放控制区 ── */
.player-controls {
  background: rgba(255, 255, 255, 0.05);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 1rem;
  padding: 1.5rem;
}

.controls-container {
  max-width: 48rem;
  margin: 0 auto;
}

.progress-indicator {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 1.5rem;
}

.progress-text {
  color: rgba(255, 255, 255, 0.6);
  font-size: 0.875rem;
}

.total-progress-bar {
  flex: 1;
  height: 0.25rem;
  background: rgba(255, 255, 255, 0.1);
  border-radius: 9999px;
  overflow: hidden;
}

.total-progress-fill {
  height: 100%;
  background: linear-gradient(to right, #8b5cf6, #3b82f6);
  transition: width 0.3s;
}

.control-buttons {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  flex-wrap: wrap;
}

.control-button {
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: 9999px;
  cursor: pointer;
  transition: all 0.3s;
  font-size: 1rem;
  font-weight: 600;
  color: #ffffff;
}

.control-button.primary {
  padding: 1rem;
  background: linear-gradient(to right, #8b5cf6, #3b82f6);
}

.control-button.primary:hover {
  opacity: 0.9;
}

.control-button.secondary {
  padding: 0.75rem;
  background: rgba(255, 255, 255, 0.1);
}

.control-button.secondary:hover:not(:disabled) {
  background: rgba(255, 255, 255, 0.2);
}

.control-button.secondary:disabled {
  opacity: 0.3;
  cursor: not-allowed;
}

.control-button:not(.primary):not(.secondary) {
  padding: 0.75rem 1rem;
  background: rgba(255, 255, 255, 0.1);
  border-radius: 0.5rem;
}

.control-button:not(.primary):not(.secondary):hover {
  background: rgba(255, 255, 255, 0.2);
}

.icon-sm {
  width: 1.25rem;
  height: 1.25rem;
}

.icon-md {
  width: 1.5rem;
  height: 1.5rem;
}

.icon-lg {
  width: 2rem;
  height: 2rem;
}

/* ── 播放完成提示 ── */
.completion-message {
  margin-top: 1.5rem;
  text-align: center;
}

.completion-text {
  margin: 0 0 1rem 0;
  font-size: 1.125rem;
}

.new-generation-button {
  padding: 0.75rem 1.5rem;
  background: linear-gradient(to right, #8b5cf6, #3b82f6);
  border: none;
  border-radius: 0.75rem;
  font-size: 1rem;
  font-weight: 600;
  color: #ffffff;
  cursor: pointer;
  transition: opacity 0.3s;
}

.new-generation-button:hover {
  opacity: 0.9;
}

/* ── 视频合成区域 ── */
.video-compose-section {
  margin-top: 1.5rem;
  padding: 1.5rem;
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 1rem;
}

.compose-header {
  display: flex;
  align-items: center;
  margin-bottom: 1rem;
}

.compose-title {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 1rem;
  font-weight: 600;
  margin: 0;
  color: #a78bfa;
}

.compose-actions {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.75rem;
}

.compose-button {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.875rem 1.5rem;
  background: linear-gradient(135deg, rgba(139, 92, 246, 0.2), rgba(59, 130, 246, 0.2));
  border: 1px solid rgba(139, 92, 246, 0.3);
  border-radius: 0.75rem;
  font-size: 1rem;
  font-weight: 500;
  color: #ffffff;
  cursor: pointer;
  transition: all 0.3s;
}

.compose-button:hover {
  background: linear-gradient(135deg, rgba(139, 92, 246, 0.3), rgba(59, 130, 246, 0.3));
  border-color: rgba(139, 92, 246, 0.5);
  transform: translateY(-1px);
}

.compose-hint {
  font-size: 0.875rem;
  color: rgba(255, 255, 255, 0.5);
  margin: 0;
  text-align: center;
}

/* 合成进度 */
.compose-progress {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.75rem;
}

.progress-icon-wrapper {
  width: 3rem;
  height: 3rem;
  display: flex;
  align-items: center;
  justify-content: center;
}

.progress-icon.spinning {
  color: #8b5cf6;
  animation: spin 1s linear infinite;
}

.progress-stage-text {
  font-size: 0.9375rem;
  color: rgba(255, 255, 255, 0.9);
  margin: 0;
  text-align: center;
}

.video-progress-bar {
  width: 100%;
  max-width: 16rem;
  height: 0.5rem;
  background: rgba(255, 255, 255, 0.1);
  border-radius: 9999px;
  overflow: hidden;
}

.video-progress-fill {
  height: 100%;
  background: linear-gradient(to right, #8b5cf6, #3b82f6);
  transition: width 0.3s;
}

.progress-detail {
  font-size: 0.875rem;
  color: rgba(255, 255, 255, 0.6);
  margin: 0;
}

/* 视频预览 */
.video-ready-section {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.video-preview-wrapper {
  position: relative;
  width: 100%;
  background: rgba(0, 0, 0, 0.3);
  border-radius: 0.75rem;
  overflow: hidden;
}

.video-player {
  width: 100%;
  display: block;
  border-radius: 0.75rem;
}

.video-actions {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  flex-wrap: wrap;
}

.download-video-button {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.75rem 1.5rem;
  background: linear-gradient(to right, #8b5cf6, #3b82f6);
  border: none;
  border-radius: 0.75rem;
  font-size: 1rem;
  font-weight: 600;
  color: #ffffff;
  cursor: pointer;
  transition: opacity 0.3s;
}

.download-video-button:hover {
  opacity: 0.9;
}

.reset-compose-button {
  padding: 0.75rem 1.5rem;
  background: rgba(255, 255, 255, 0.1);
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 0.75rem;
  font-size: 1rem;
  font-weight: 500;
  color: #ffffff;
  cursor: pointer;
  transition: all 0.3s;
}

.reset-compose-button:hover {
  background: rgba(255, 255, 255, 0.15);
}

/* 合成错误 */
.compose-error {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.75rem;
  padding: 1rem;
  background: rgba(239, 68, 68, 0.1);
  border: 1px solid rgba(239, 68, 68, 0.2);
  border-radius: 0.75rem;
}

.error-icon-sm {
  width: 2rem;
  height: 2rem;
  color: #ef4444;
}

.error-text {
  font-size: 0.9375rem;
  color: #f87171;
  margin: 0;
  text-align: center;
}

.retry-compose-button {
  padding: 0.5rem 1.25rem;
  background: rgba(239, 68, 68, 0.2);
  border: 1px solid rgba(239, 68, 68, 0.3);
  border-radius: 0.5rem;
  font-size: 0.875rem;
  font-weight: 500;
  color: #f87171;
  cursor: pointer;
  transition: all 0.3s;
}

.retry-compose-button:hover {
  background: rgba(239, 68, 68, 0.3);
}

/* ── 自定义滚动条 ── */
::-webkit-scrollbar {
  width: 8px;
  height: 8px;
}

::-webkit-scrollbar-track {
  background: rgba(255, 255, 255, 0.05);
  border-radius: 4px;
}

::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, 0.1);
  border-radius: 4px;
}

::-webkit-scrollbar-thumb:hover {
  background: rgba(255, 255, 255, 0.2);
}
</style>
