<template>
  <div class="design-preview">
    <!-- 视角 Tab 栏（多图时显示） -->
    <div class="view-tabs" v-if="hasMultipleViews">
      <button
        v-for="(img, idx) in design.images"
        :key="img.id"
        class="view-tab"
        :class="{ active: activeViewIndex === idx }"
        @click="activeViewIndex = idx"
      >
        {{ img.view_name }}
      </button>
    </div>

    <!-- 图片预览区 -->
    <div class="preview-container">
      <div class="image-wrapper" :style="{ transform: `scale(${scale})` }">
        <el-image
          :src="currentImageUrl"
          :alt="design.prompt"
          fit="contain"
          :preview-src-list="allImageUrls"
          :initial-index="activeViewIndex"
          preview-teleported
          class="design-image"
        >
          <template #placeholder>
            <div class="image-placeholder">
              <el-icon class="loading-icon"><Loading /></el-icon>
              <span>加载中...</span>
            </div>
          </template>
          <template #error>
            <div class="image-error">
              <el-icon><PictureFilled /></el-icon>
              <span>图片加载失败</span>
            </div>
          </template>
        </el-image>
      </div>
      
      <!-- 视角指示器（多图时显示） -->
      <div class="view-indicator" v-if="hasMultipleViews">
        <span class="indicator-text">{{ activeViewName }} ({{ activeViewIndex + 1 }}/{{ design.images.length }})</span>
      </div>

      <!-- 缩放控制 -->
      <div class="zoom-controls">
        <button class="zoom-btn" @click="zoomOut" :disabled="scale <= 0.5">
          <el-icon><ZoomOut /></el-icon>
        </button>
        <span class="zoom-level">{{ Math.round(scale * 100) }}%</span>
        <button class="zoom-btn" @click="zoomIn" :disabled="scale >= 2">
          <el-icon><ZoomIn /></el-icon>
        </button>
        <button class="zoom-btn reset-btn" @click="resetZoom" v-if="scale !== 1">
          <el-icon><RefreshRight /></el-icon>
        </button>
      </div>
    </div>

    <!-- 360° 旋转展示区（基于3D模型） -->
    <div class="model3d-section" v-if="has3DModel || generating3D">
      <h4 class="section-title">360° 旋转展示</h4>
      <div v-if="generating3D" class="generating-state">
        <el-icon class="loading-icon"><Loading /></el-icon>
        <span>正在生成 3D 模型，请稍候...</span>
      </div>
      <div v-else-if="current3DModelUrl" class="model-viewer-wrapper">
        <model-viewer
          ref="modelViewerRef"
          :src="current3DModelUrl"
          alt="玉雕 3D 模型"
          auto-rotate
          auto-rotate-delay="0"
          rotation-per-second="36deg"
          camera-controls
          shadow-intensity="1"
          environment-image="neutral"
          exposure="1.2"
          style="width: 100%; height: 500px;"
        />
      </div>
      <!-- 3D 模型已生成时显示操作按钮 -->
      <div v-if="current3DModelUrl && !generating3D" class="model3d-actions">
        <button class="model3d-action-btn" @click="handleDownload3DModel">
          <el-icon><Download /></el-icon>
          <span>下载3D模型</span>
        </button>
        <button class="model3d-action-btn" @click="handleRecordVideo" :disabled="recording">
          <el-icon><VideoCameraFilled /></el-icon>
          <span>{{ recording ? `录制中... ${recordProgress}%` : '录制展示视频' }}</span>
        </button>
        <button class="model3d-action-btn" @click="handleRegen3D">
          <el-icon><RefreshRight /></el-icon>
          <span>重新生成</span>
        </button>
      </div>
    </div>

    <!-- 展示视频区域 -->
    <div class="video-section" v-if="design.video_url || generatingVideo">
      <h4 class="section-title">展示视频</h4>
      <div v-if="generatingVideo" class="generating-state">
        <el-icon class="loading-icon"><Loading /></el-icon>
        <span>正在生成展示视频，预计需要 2-5 分钟...</span>
      </div>
      <div v-else-if="design.video_url" class="video-wrapper">
        <video
          :key="design.video_url"
          controls
          preload="auto"
          crossorigin="anonymous"
          class="preview-video"
        >
          <source :src="design.video_url" type="video/mp4" />
          您的浏览器不支持视频播放
        </video>
        <div class="video-actions">
          <button class="model3d-action-btn" @click="handleDownloadVideo">
            <el-icon><Download /></el-icon>
            <span>下载视频</span>
          </button>
          <button class="model3d-action-btn" @click="handleRegenVideo">
            <el-icon><RefreshRight /></el-icon>
            <span>重新生成</span>
          </button>
        </div>
      </div>
    </div>

    <div class="design-info">
      <h4 class="info-title">设计详情</h4>
      <div class="info-grid">
        <div class="info-item">
          <span class="info-label">品类</span>
          <span class="info-value">{{ design.category?.name || '-' }}</span>
        </div>
        <div class="info-item" v-if="design.sub_type">
          <span class="info-label">类型</span>
          <span class="info-value">{{ design.sub_type.name }}</span>
        </div>
        <div class="info-item" v-if="design.color">
          <span class="info-label">颜色</span>
          <span class="info-value">{{ design.color.name }}</span>
        </div>
        <div class="info-item full-width">
          <span class="info-label">设计需求</span>
          <span class="info-value prompt">{{ design.prompt }}</span>
        </div>
      </div>
    </div>

    <!-- 操作按钮 -->
    <div class="action-buttons">
      <button
        class="action-btn download-btn"
        @click="handleDownload"
        :disabled="downloading"
      >
        <el-icon><Download /></el-icon>
        <span>{{ downloading ? '下载中...' : '下载设计图' }}</span>
      </button>
      <!-- 生成 3D 模型按钮 -->
      <button
        v-if="!has3DModel && !generating3D"
        class="action-btn model3d-btn"
        @click="handleGenerate3D"
        :disabled="generating3D"
      >
        <el-icon><Platform /></el-icon>
        <span>生成3D模型</span>
      </button>
      <!-- 生成展示视频按钮 -->
      <button
        v-if="!design.video_url && !generatingVideo"
        class="action-btn video-btn"
        @click="handleGenerateVideo"
      >
        <el-icon><VideoCameraFilled /></el-icon>
        <span>生成展示视频</span>
      </button>
      <button class="action-btn secondary-btn" @click="goToUserCenter">
        <el-icon><User /></el-icon>
        <span>查看我的设计</span>
      </button>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, watch } from 'vue'
import { useRouter } from 'vue-router'
import { Loading, PictureFilled, ZoomIn, ZoomOut, RefreshRight, Download, User, Platform, VideoCameraFilled } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
import type { Design } from '@/stores/design'
import { getDesignDownloadUrl, generate3DModelApi, generateVideoApi } from '@/api/design'
import request from '@/api/request'

const props = defineProps<{
  design: Design
}>()

const router = useRouter()

// model-viewer ref
const modelViewerRef = ref<any>(null)

// 录制状态
const recording = ref(false)
const recordProgress = ref(0)

// 当前视角索引
const activeViewIndex = ref(0)

// 缩放比例
const scale = ref(1)

// 3D 模型生成状态
const generating3D = ref(false)

// 视频生成状态
const generatingVideo = ref(false)

// 是否有多视角图片
const hasMultipleViews = computed(() => {
  return props.design.images && props.design.images.length > 1
})

// 当前视角名称
const activeViewName = computed(() => {
  if (props.design.images && props.design.images.length > 0) {
    return props.design.images[activeViewIndex.value]?.view_name || ''
  }
  return ''
})

// 是否有 3D 模型
const has3DModel = computed(() => {
  if (props.design.images && props.design.images.length > 0) {
    return props.design.images.some(img => !!img.model_3d_url)
  }
  return false
})

// 当前视角的 3D 模型 URL
const current3DModelUrl = computed(() => {
  if (props.design.images && props.design.images.length > 0) {
    const img = props.design.images[activeViewIndex.value]
    if (img?.model_3d_url) return img.model_3d_url
    // fallback 到第一张有 3D 模型的图
    const withModel = props.design.images.find(i => !!i.model_3d_url)
    return withModel?.model_3d_url || ''
  }
  return ''
})

// 生成 3D 模型
const handleGenerate3D = async () => {
  generating3D.value = true
  try {
    const updated = await generate3DModelApi(props.design.id)
    if (updated.images) {
      updated.images.forEach((img: any, idx: number) => {
        if (props.design.images[idx]) {
          props.design.images[idx].model_3d_url = img.model_3d_url
        }
      })
    }
    ElMessage.success('3D 模型生成成功！')
  } catch (e: any) {
    ElMessage.error(e?.response?.data?.detail || '3D 模型生成失败，请重试')
  } finally {
    generating3D.value = false
  }
}

// 重新生成 3D 模型
const handleRegen3D = async () => {
  generating3D.value = true
  try {
    const updated = await generate3DModelApi(props.design.id, true)
    if (updated.images) {
      updated.images.forEach((img: any, idx: number) => {
        if (props.design.images[idx]) {
          props.design.images[idx].model_3d_url = img.model_3d_url
        }
      })
    }
    ElMessage.success('3D 模型重新生成成功！')
  } catch (e: any) {
    ElMessage.error(e?.response?.data?.detail || '3D 模型重新生成失败')
  } finally {
    generating3D.value = false
  }
}

// 生成展示视频
const handleGenerateVideo = async () => {
  generatingVideo.value = true
  try {
    const updated = await generateVideoApi(props.design.id)
    if (updated.video_url) {
      props.design.video_url = updated.video_url
    }
    ElMessage.success('展示视频生成成功！')
  } catch (e: any) {
    ElMessage.error(e?.response?.data?.detail || e?.detail || '视频生成失败，请重试')
  } finally {
    generatingVideo.value = false
  }
}

// 重新生成展示视频
const handleRegenVideo = async () => {
  generatingVideo.value = true
  try {
    const updated = await generateVideoApi(props.design.id, true)
    if (updated.video_url) {
      props.design.video_url = updated.video_url
    }
    ElMessage.success('展示视频重新生成成功！')
  } catch (e: any) {
    ElMessage.error(e?.response?.data?.detail || '视频重新生成失败')
  } finally {
    generatingVideo.value = false
  }
}

// 下载展示视频
const handleDownloadVideo = async () => {
  const videoUrl = props.design.video_url
  if (!videoUrl) return
  try {
    const res = await fetch(videoUrl)
    if (!res.ok) throw new Error('下载失败')
    const blob = await res.blob()
    const category = props.design.category?.name || '设计'
    const subType = props.design.sub_type?.name || ''
    const filename = `${category}${subType ? '-' + subType : ''}-展示视频-${props.design.id}.mp4`
    _downloadBlob(blob, filename)
    ElMessage.success('视频下载成功')
  } catch {
    ElMessage.error('视频下载失败')
  }
}

// 获取图片URL
const toImageUrl = (url: string | null): string => {
  if (!url) return ''
  if (url.startsWith('http')) return url
  // /uploads 路径已由 Vite 代理到后端，不需要加 /api 前缀
  if (url.startsWith('/uploads')) return url
  return url
}

// 当前显示的图片URL
const currentImageUrl = computed(() => {
  // 优先用多视角图片
  if (props.design.images && props.design.images.length > 0) {
    return toImageUrl(props.design.images[activeViewIndex.value]?.image_url)
  }
  // 兼容旧数据，使用单图
  return toImageUrl(props.design.image_url)
})

// 所有图片URL（用于大图预览）
const allImageUrls = computed(() => {
  if (props.design.images && props.design.images.length > 0) {
    return props.design.images.map(img => toImageUrl(img.image_url))
  }
  return [toImageUrl(props.design.image_url)]
})

// 下载状态
const downloading = ref(false)

// 下载文件名
const downloadFilename = computed(() => {
  const category = props.design.category?.name || '设计'
  const subType = props.design.sub_type?.name || ''
  const viewSuffix = hasMultipleViews.value ? `-${activeViewName.value}` : ''
  return `${category}${subType ? '-' + subType : ''}${viewSuffix}-${props.design.id}.png`
})

// 下载设计图
const handleDownload = () => {
  const imgUrl = currentImageUrl.value
  if (!imgUrl) {
    ElMessage.error('图片不存在')
    return
  }
  // 远程 URL 直接新窗口打开（用户右键可保存）
  if (imgUrl.startsWith('http')) {
    window.open(imgUrl, '_blank')
    return
  }
  // 本地文件通过 axios 携带 Token 下载
  downloading.value = true
  request.get(getDesignDownloadUrl(props.design.id), {
    responseType: 'blob'
  }).then((response: any) => {
    const blob = new Blob([response], { type: 'image/png' })
    const url = window.URL.createObjectURL(blob)
    const link = document.createElement('a')
    link.href = url
    link.download = downloadFilename.value
    document.body.appendChild(link)
    link.click()
    document.body.removeChild(link)
    window.URL.revokeObjectURL(url)
    ElMessage.success('下载成功')
  }).catch(() => {
    ElMessage.error('下载失败，请重试')
  }).finally(() => {
    downloading.value = false
  })
}

// 切换视角时重置缩放
watch(activeViewIndex, () => {
  scale.value = 1
})

// 放大
const zoomIn = () => {
  if (scale.value < 2) {
    scale.value = Math.min(2, scale.value + 0.25)
  }
}

// 缩小
const zoomOut = () => {
  if (scale.value > 0.5) {
    scale.value = Math.max(0.5, scale.value - 0.25)
  }
}

// 重置缩放
const resetZoom = () => {
  scale.value = 1
}

// 下载 3D 模型 zip 包
const handleDownload3DModel = async () => {
  const glbUrl = current3DModelUrl.value
  if (!glbUrl) {
    ElMessage.error('3D 模型不存在')
    return
  }
  const category = props.design.category?.name || '设计'
  const subType = props.design.sub_type?.name || ''

  // 先尝试下载 zip 包（同名不同后缀），注意不能用 request（会加 /api 前缀）
  const zipUrl = glbUrl.replace(/\.glb$/, '.zip')
  try {
    const zipRes = await fetch(zipUrl)
    if (zipRes.ok) {
      const blob = await zipRes.blob()
      const filename = `${category}${subType ? '-' + subType : ''}-3D模型-${props.design.id}.zip`
      _downloadBlob(blob, filename)
      ElMessage.success('3D 模型包下载成功')
      return
    }
  } catch {
    // zip 不存在，继续尝试 glb
  }

  // zip 不存在，下载 glb
  try {
    const glbRes = await fetch(glbUrl)
    if (!glbRes.ok) throw new Error('下载失败')
    const blob = await glbRes.blob()
    const filename = `${category}${subType ? '-' + subType : ''}-3D模型-${props.design.id}.glb`
    _downloadBlob(blob, filename)
    ElMessage.success('3D 模型下载成功')
  } catch {
    ElMessage.error('3D 模型下载失败')
  }
}

// 通用 Blob 下载工具
const _downloadBlob = (blobData: any, filename: string) => {
  const blob = new Blob([blobData])
  const url = window.URL.createObjectURL(blob)
  const link = document.createElement('a')
  link.href = url
  link.download = filename
  document.body.appendChild(link)
  link.click()
  document.body.removeChild(link)
  window.URL.revokeObjectURL(url)
}

// 录制 model-viewer 旋转一圈的展示视频
// 程序化控制旋转角度 + toDataURL 逐帧截图（WebGL canvas 无法直接 captureStream/drawImage）
const handleRecordVideo = async () => {
  const mv = modelViewerRef.value as any
  if (!mv) {
    ElMessage.error('3D 模型未加载')
    return
  }

  recording.value = true
  recordProgress.value = 0
  ElMessage.info('正在录制展示视频，请稍候...')

  try {
    // 获取画布尺寸
    const srcCanvas = mv.shadowRoot?.querySelector('canvas') as HTMLCanvasElement
    const width = srcCanvas?.width || 800
    const height = srcCanvas?.height || 600

    // 创建 2D 中转 canvas
    const recordCanvas = document.createElement('canvas')
    recordCanvas.width = width
    recordCanvas.height = height
    const ctx = recordCanvas.getContext('2d')!

    // 视频参数
    const totalFrames = 180 // 6秒 x 30fps
    const fps = 30
    const stream = recordCanvas.captureStream(fps)

    const mimeType = MediaRecorder.isTypeSupported('video/webm;codecs=vp9')
      ? 'video/webm;codecs=vp9'
      : 'video/webm'

    const recorder = new MediaRecorder(stream, {
      mimeType,
      videoBitsPerSecond: 5000000
    })
    const chunks: Blob[] = []

    recorder.ondataavailable = (e) => {
      if (e.data.size > 0) chunks.push(e.data)
    }

    recorder.onstop = () => {
      // 恢复自动旋转
      mv.setAttribute('auto-rotate', '')
      mv.removeAttribute('interaction-prompt')

      const blob = new Blob(chunks, { type: mimeType })
      if (blob.size < 1000) {
        ElMessage.error('视频录制失败，文件为空')
        recording.value = false
        return
      }
      const category = props.design.category?.name || '设计'
      const subType = props.design.sub_type?.name || ''
      const filename = `${category}${subType ? '-' + subType : ''}-360度展示-${props.design.id}.webm`
      _downloadBlob(blob, filename)
      recording.value = false
      recordProgress.value = 0
      ElMessage.success('展示视频已下载')
    }

    // 暂停自动旋转，由程序控制角度
    mv.removeAttribute('auto-rotate')
    mv.setAttribute('interaction-prompt', 'none')

    // 开始录制
    recorder.start(100)

    // 逐帧旋转 + 截图
    for (let frame = 0; frame < totalFrames; frame++) {
      const angle = (frame / totalFrames) * 360
      // 设置相机轨道位置（水平角度 垂直角度 距离）
      mv.cameraOrbit = `${angle}deg 75deg auto`

      // 等待渲染
      await new Promise<void>(resolve => {
        requestAnimationFrame(() => {
          requestAnimationFrame(() => resolve())
        })
      })

      // 用 model-viewer 的 toDataURL 截图（内部会处理 preserveDrawingBuffer）
      try {
        const dataUrl = mv.toDataURL('image/jpeg', 0.85)
        const img = new Image()
        img.src = dataUrl
        await img.decode()
        ctx.drawImage(img, 0, 0, width, height)
      } catch {
        // 忽略单帧失败
      }

      recordProgress.value = Math.round(((frame + 1) / totalFrames) * 100)
    }

    // 录制完成
    recorder.stop()

  } catch (e: any) {
    // 恢复自动旋转
    mv.setAttribute('auto-rotate', '')
    mv.removeAttribute('interaction-prompt')
    ElMessage.error(e.message || '录制视频失败')
    recording.value = false
    recordProgress.value = 0
  }
}

// 跳转到用户中心
const goToUserCenter = () => {
  ElMessage.success('设计已自动保存到您的设计历史中')
  router.push('/user')
}
</script>

<style scoped lang="scss">
$primary-color: #5B7E6B;
$primary-light: #8BAF9C;
$secondary-color: #C4A86C;
$bg-color: #FAF8F5;
$bg-dark: #F0EDE8;
$border-color: #E8E4DF;
$text-primary: #2C2C2C;
$text-secondary: #6B6B6B;
$text-light: #999999;

.design-preview {
  display: flex;
  flex-direction: column;
  gap: 24px;
}

.view-tabs {
  display: flex;
  gap: 8px;
  padding: 4px;
  background: #fff;
  border-radius: 10px;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
}

.view-tab {
  flex: 1;
  padding: 10px 16px;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 8px;
  font-size: 14px;
  color: $text-secondary;
  cursor: pointer;
  transition: all 0.25s ease;
  letter-spacing: 1px;

  &:hover {
    color: $primary-color;
    background: rgba($primary-color, 0.05);
  }

  &.active {
    background: $primary-color;
    color: #fff;
    border-color: $primary-color;
    font-weight: 500;
  }
}

.view-indicator {
  position: absolute;
  top: 16px;
  left: 16px;
  background: rgba(0, 0, 0, 0.5);
  padding: 4px 12px;
  border-radius: 12px;
}

.indicator-text {
  font-size: 12px;
  color: #fff;
}

.preview-container {
  position: relative;
  background: #fff;
  border-radius: 12px;
  padding: 24px;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
  overflow: hidden;
}

.image-wrapper {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 300px;
  max-height: 500px;
  transition: transform 0.3s ease;
  transform-origin: center center;
}

.design-image {
  max-width: 100%;
  max-height: 450px;
  border-radius: 8px;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
  cursor: zoom-in;
  
  :deep(img) {
    max-width: 100%;
    max-height: 450px;
    object-fit: contain;
  }
}

.image-placeholder,
.image-error {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  width: 300px;
  height: 300px;
  background: $bg-color;
  border-radius: 8px;
  color: $text-light;
  
  .el-icon {
    font-size: 48px;
  }
}

.loading-icon {
  animation: spin 1s linear infinite;
}

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

.zoom-controls {
  position: absolute;
  bottom: 16px;
  right: 16px;
  display: flex;
  align-items: center;
  gap: 8px;
  background: rgba(255, 255, 255, 0.95);
  padding: 8px 12px;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

.zoom-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  background: transparent;
  border: 1px solid $border-color;
  border-radius: 6px;
  cursor: pointer;
  color: $text-secondary;
  transition: all 0.2s ease;
  
  &:hover:not(:disabled) {
    background: $primary-color;
    border-color: $primary-color;
    color: #fff;
  }
  
  &:disabled {
    opacity: 0.4;
    cursor: not-allowed;
  }
}

.zoom-level {
  min-width: 48px;
  text-align: center;
  font-size: 13px;
  color: $text-secondary;
}

.design-info {
  background: #fff;
  border-radius: 12px;
  padding: 20px 24px;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
}

.info-title {
  font-size: 15px;
  font-weight: 500;
  color: $text-primary;
  margin: 0 0 16px 0;
  padding-bottom: 12px;
  border-bottom: 1px solid $border-color;
  letter-spacing: 1px;
}

.info-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 16px;
}

.info-item {
  display: flex;
  flex-direction: column;
  gap: 6px;
  
  &.full-width {
    grid-column: 1 / -1;
  }
}

.info-label {
  font-size: 12px;
  color: $text-light;
  letter-spacing: 0.5px;
}

.info-value {
  font-size: 14px;
  color: $text-primary;
  
  &.prompt {
    line-height: 1.6;
    color: $text-secondary;
  }
}

.action-buttons {
  display: flex;
  gap: 16px;
  flex-wrap: wrap;
}

.action-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 14px 28px;
  border-radius: 8px;
  font-size: 15px;
  cursor: pointer;
  transition: all 0.25s ease;
  text-decoration: none;
  letter-spacing: 1px;
  
  .el-icon {
    font-size: 18px;
  }
}

.download-btn {
  background: $primary-color;
  color: #fff;
  border: none;
  
  &:hover {
    background: #4a6a5a;
    transform: translateY(-2px);
    box-shadow: 0 4px 12px rgba($primary-color, 0.3);
  }
}

.secondary-btn {
  background: #fff;
  color: $primary-color;
  border: 1px solid $primary-color;
  
  &:hover {
    background: $primary-color;
    color: #fff;
  }
}

.model3d-btn {
  background: #8E44AD;
  color: #fff;
  border: none;
  
  &:hover:not(:disabled) {
    background: #7D3C98;
    transform: translateY(-2px);
    box-shadow: 0 4px 12px rgba(#8E44AD, 0.3);
  }
  
  &:disabled {
    opacity: 0.6;
    cursor: not-allowed;
  }
}

.model3d-section {
  background: #fff;
  border-radius: 12px;
  padding: 20px 24px;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
}

.section-title {
  font-size: 15px;
  font-weight: 500;
  color: $text-primary;
  margin: 0 0 16px 0;
  padding-bottom: 12px;
  border-bottom: 1px solid $border-color;
  letter-spacing: 1px;
}

.generating-state {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding: 40px 0;
  color: $text-secondary;
  font-size: 14px;
}

.model3d-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  padding: 12px 0 0;
  flex-wrap: wrap;
}

.model3d-action-btn {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 6px 14px;
  font-size: 12px;
  color: #666;
  background: #f5f5f5;
  border: 1px solid #e0e0e0;
  border-radius: 6px;
  cursor: pointer;
  transition: all 0.2s;

  &:hover {
    color: $primary-color;
    border-color: $primary-color;
    background: rgba($primary-color, 0.05);
  }

  &:disabled {
    cursor: not-allowed;
    opacity: 0.6;
    color: $secondary-color;
    border-color: $secondary-color;
  }
}

.model-viewer-wrapper {
  border-radius: 8px;
  overflow: hidden;
  background: $bg-color;
}

// 视频区域样式
.video-section {
  background: #fff;
  border-radius: 12px;
  padding: 20px 24px;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
}

.video-wrapper {
  border-radius: 8px;
  overflow: hidden;
  background: #000;
}

.preview-video {
  width: 100%;
  max-height: 500px;
  display: block;
}

.video-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  padding: 12px 0 0;
  background: #fff;
}

.video-btn {
  background: linear-gradient(135deg, #e040fb 0%, #7c4dff 100%) !important;
  color: #fff !important;
  border: none !important;

  &:hover {
    opacity: 0.9;
    transform: translateY(-1px);
  }
}
</style>
