<template>
  <FullWidthLayout :show-padding="false">
    <div class="digital-human-page">
      <!-- 左侧配置区 -->
      <section class="config-panel">

        <!-- 步骤1：输入文案 -->
        <div class="config-card">
          <div class="step-indicator">1</div>
          <h3 class="card-title">输入播文案</h3>

          <a-textarea
            v-model:value="ttsText"
            :placeholder="textareaPlaceholder"
            :rows="4"
            :maxlength="maxTextLength"
            :show-count="true"
            class="text-input"
            :bordered="false"
          />

          <div class="input-meta">
            <span>当前字数：{{ ttsText?.length || 0 }}字</span>
            <span>预计音频时长：<span class="meta-value">{{ audioDurationSec }}秒</span></span>
          </div>
        </div>

        <!-- 步骤2：语音设置 -->
        <div class="config-card">
          <div class="step-indicator">2</div>
          <h3 class="card-title">语音设置</h3>

          <div class="voice-settings">
            <div class="setting-group">
              <label class="setting-label">选择音色</label>
              <VoiceSelector
                :synth-text="ttsText"
                :speech-rate="speechRate"
                @select="handleVoiceSelect"
              />
            </div>

            <div class="setting-group">
              <label class="setting-label">合成模型等级</label>
              <div class="model-options">
                <button
                  class="model-btn"
                  :class="{ 'model-btn--active': speechRate <= 1 }"
                >
                  标准版 (1x积分)
                </button>
                <button
                  class="model-btn model-btn--pro"
                  :class="{ 'model-btn--active': speechRate > 1 }"
                >
                  Pro 旗舰版 (3x积分)
                  <CrownFilled class="pro-icon" />
                </button>
              </div>
            </div>
          </div>
        </div>

        <!-- 步骤3：上传视频 -->
        <div class="config-card">
          <div class="step-indicator">3</div>
          <h3 class="card-title">上传/选择视频素材</h3>

          <div class="video-options">
            <!-- 上传新视频 -->
            <div
              class="video-option-card"
              :class="{ 'video-option-card--selected': videoState.videoSource === 'upload' }"
              @click="handleSelectUpload"
            >
              <div class="video-option-icon">
                <CloudUploadOutlined />
              </div>
              <div class="video-option-content">
                <h4>点击上传新视频</h4>
                <p>支持 MP4、MOV (需 >3秒)</p>
              </div>
            </div>

            <!-- 从素材库选择 -->
            <div
              class="video-option-card"
              :class="{ 'video-option-card--selected': videoState.videoSource === 'select' }"
              @click="handleSelectFromLibrary"
            >
              <div class="video-option-icon">
                <PictureOutlined />
              </div>
              <div class="video-option-content">
                <h4>从素材库选择</h4>
                <p>选择已上传的视频</p>
              </div>
            </div>
          </div>

          <!-- 已选择视频预览 -->
          <div v-if="videoState.selectedVideo" class="selected-video">
            <div class="video-preview-thumb">
              <img
                :src="getVideoPreviewUrl(videoState.selectedVideo)"
                :alt="videoState.selectedVideo.fileName"
              />
            </div>
            <div class="video-preview-info">
              <div class="video-name">{{ videoState.selectedVideo.fileName }}</div>
              <div class="video-meta">{{ formatDuration(videoState.selectedVideo.duration) }}</div>
            </div>
            <button class="change-video-btn" @click="replaceVideo">更换</button>
          </div>

          <!-- 上传区域 -->
          <div
            v-if="videoState.videoSource === 'upload'"
            class="upload-zone"
            :class="{ 'upload-zone--dragover': dragOver }"
            @drop.prevent="handleDrop"
            @dragover.prevent="dragOver = true"
            @dragleave.prevent="dragOver = false"
          >
            <input ref="fileInput" type="file" accept=".mp4,.mov" class="file-input" @change="handleFileSelectWrapper" />

            <div v-if="!videoState.uploadedVideo" class="upload-placeholder">
              <CloudUploadOutlined class="upload-icon" />
              <span class="upload-text">点击上传新视频</span>
              <span class="upload-hint">支持 MP4、MOV (需 >3秒)</span>
              <button class="select-file-btn" @click="triggerFileSelect">选择文件</button>
            </div>

            <div v-else class="upload-preview">
              <video :src="videoState.uploadedVideo" controls class="preview-video-player"></video>
              <p class="upload-filename">{{ videoState.videoFile?.name }}</p>
              <button class="change-video-btn" @click="replaceVideo">更换</button>
            </div>
          </div>
        </div>

        <!-- Pipeline 进度 -->
        <PipelineProgress
          v-if="isPipelineBusy || isPipelineReady || isPipelineFailed || isPipelineCompleted"
          :state="pipelineState"
          :progress="pipelineProgress"
          :is-busy="isPipelineBusy"
          :is-ready="isPipelineReady"
          :is-failed="isPipelineFailed"
          :is-completed="isPipelineCompleted"
          :error="pipelineError"
          @retry="retryPipeline"
          @reset="resetPipeline"
        />

        <!-- 操作按钮 -->
        <div class="action-section">
          <a-button
            v-if="!isPipelineCompleted"
            type="primary"
            size="large"
            :disabled="!canGenerate"
            :loading="isPipelineBusy"
            block
            @click="generateAudio"
            class="action-btn"
          >
            {{ isPipelineBusy ? pipelineStateLabel + '...' : '生成数字人视频' }}
          </a-button>

          <div v-else class="completed-tip">
            <span>任务已提交成功</span>
            <a-button @click="resetPipeline" class="reset-btn">重新生成</a-button>
          </div>
        </div>

      </section>

      <!-- 右侧预览区 -->
      <aside class="preview-panel">
        <div class="preview-card">
          <h3 class="preview-title">合成预览</h3>

          <div class="preview-screen">
            <ResultPanel @videoLoaded="handleVideoLoaded" />
          </div>

          <div class="preview-meta">
            <div class="meta-row">
              <span class="meta-label">预计消耗积分</span>
              <span class="meta-value">150 积分</span>
            </div>
            <div class="meta-row">
              <span class="meta-label">当前余额</span>
              <span class="meta-value">{{ userStore.remainingPoints.toLocaleString() }} 积分</span>
            </div>
          </div>
        </div>
      </aside>

    </div>

    <!-- 视频选择器弹窗 -->
    <VideoSelector v-model:open="videoState.selectorVisible" @select="handleVideoSelect" />
  </FullWidthLayout>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { CloudUploadOutlined, CrownFilled } from '@ant-design/icons-vue'
import { useVoiceCopyStore } from '@/stores/voiceCopy'
import { useUserStore } from '@/stores/user'
import VideoSelector from '@/components/VideoSelector.vue'
import VoiceSelector from '@/components/VoiceSelector.vue'
import ResultPanel from '@/components/ResultPanel.vue'
import FullWidthLayout from '@/layouts/components/FullWidthLayout.vue'
import PipelineProgress from '@/components/PipelineProgress.vue'

// Controller Hook
import { useIdentifyFaceController } from './hooks/useIdentifyFaceController'

const voiceStore = useVoiceCopyStore()
const userStore = useUserStore()
const dragOver = ref(false)

// ==================== 初始化 Controller ====================

// Controller 内部直接创建和管理两个子 Hook
const controller = useIdentifyFaceController()

// 解构 controller 以简化模板调用
const {
  // 语音生成相关
  ttsText,
  speechRate,
  generateAudio,

  // 数字人生成相关
  videoState,
  getVideoPreviewUrl,

  // 计算属性
  canGenerate,
  maxTextLength,
  textareaPlaceholder,
  audioDurationSec,

  // Pipeline 状态（单一状态源）
  pipelineState,
  pipelineStateLabel,
  isPipelineBusy,
  isPipelineReady,
  isPipelineFailed,
  isPipelineCompleted,
  pipelineProgress,
  pipelineError,
  retryPipeline,
  resetPipeline,

  // 事件处理方法
  handleVoiceSelect,
  handleDrop,
  handleSelectUpload,
  handleSelectFromLibrary,
  handleVideoSelect,
  handleVideoLoaded,
  replaceVideo,

  // UI 辅助方法
  formatDuration,
} = controller

// ==================== 生命周期 ====================

// 引用 fileInput 用于手动触发点击
const fileInput = ref<HTMLInputElement | null>(null)

// 触发文件选择
const triggerFileSelect = () => {
  fileInput.value?.click()
}

// 覆盖 controller 中的方法，使用 ref
const handleFileSelectWrapper = (e: Event) => {
  controller.handleFileSelect(e)
}

// ==================== 生命周期 ====================

import { onMounted } from 'vue'
onMounted(async () => {
  await voiceStore.refresh()
})
</script>

<style scoped lang="less">
.digital-human-page {
  min-height: 100vh;
  background: #F8FAFC;
  display: flex;
  flex-direction: row;
  gap: 24px;
  padding: 24px;
}

// 布局容器
.config-panel {
  flex: 1;
  padding:0 20px;
  max-width: 100%;
}

.preview-panel {
  width: 400px;
  background: #fff;
  border-left: 1px solid #E2E8F0;
  padding: 20px;
  display: flex;
  flex-direction: column;
  flex-shrink: 0;

  @media (max-width: 1200px) {
    width: 100%;
    border-left: none;
    border-top: 1px solid #E2E8F0;
    order: -1;
  }
}

// 配置卡片
.config-card {
  position: relative;
  background: #fff;
  border: 1px solid #E2E8F0;
  border-radius: 12px;
  padding: 20px;
  margin-bottom: 16px;
  overflow: hidden;
}

.step-indicator {
  position: absolute;
  left: 0;
  top: 0;
  width: 32px;
  height: 32px;
  background: linear-gradient(135deg, #3B82F6 0%, #2563EB 100%);
  color: #fff;
  border-radius: 8px 0 12px 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 14px;
  font-weight: 700;
  box-shadow: 0 2px 8px rgba(59, 130, 246, 0.3);
}

.card-title {
  font-size: 16px;
  font-weight: 600;
  color: #1E293B;
  margin: 0 0 12px 12px;
  padding-left: 44px;
}

// 文案输入
.text-input {
  width: 100%;

  :deep(.ant-input) {
    border: none;
    border-radius: 8px;
    font-size: 14px;
    padding: 16px 12px;
    background: #F8FAFC;

    &:focus {
      background: #fff;
      box-shadow: 0 0 0 1px #E2E8F0;
    }

    :deep(.ant-input-textarea-show-count) {
      bottom: 8px;
    }
  }
}

.input-meta {
  display: flex;
  justify-content: space-between;
  font-size: 12px;
  color: #94A3B8;
  margin-top: 12px;
}

.meta-value {
  font-weight: 600;
  color: #1E293B;
}

// 语音设置
.voice-settings {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;

  @media (max-width: 640px) {
    grid-template-columns: 1fr;
  }
}

.setting-group {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.setting-label {
  font-size: 13px;
  font-weight: 500;
  color: #64748B;
}

.model-options {
  display: flex;
  background: #F1F5F9;
  border-radius: 6px;
  padding: 2px;
  gap: 2px;
}

.model-btn {
  flex: 1;
  padding: 8px 10px;
  border-radius: 6px;
  font-size: 12px;
  font-weight: 500;
  color: #64748B;
  border: none;
  background: transparent;
  cursor: pointer;
  transition: all 0.2s ease;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4px;

  &:hover {
    background: rgba(255, 255, 255, 0.5);
  }

  &--active {
    background: #fff;
    color: #22C55E;
    font-weight: 600;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
  }
}

.pro-icon {
  font-size: 12px;
  color: #EAB308;
}

// 视频选项
.video-options {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
  margin-bottom: 16px;

  @media (max-width: 480px) {
    grid-template-columns: 1fr;
  }
}

.video-option-card {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 16px;
  border: 2px dashed #E2E8F0;
  border-radius: 10px;
  background: #F8FAFC;
  cursor: pointer;
  transition: all 0.2s ease;

  &:hover {
    border-color: #3B82F6;
    background: #EFF6FF;
  }

  &--selected {
    border-style: solid;
    border-color: #2563EB;
    background: #EFF6FF;
  }
}

.video-option-icon {
  font-size: 20px;
  color: #94A3B8;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  background: #fff;
  border-radius: 6px;
  flex-shrink: 0;
}

.video-option-content {
  flex: 1;
}

.video-option-content h4 {
  font-size: 13px;
  font-weight: 500;
  color: #1E293B;
  margin: 0 0 4px 0;
}

.video-option-content p {
  font-size: 11px;
  color: #94A3B8;
  margin: 0;
}

// 已选择视频
.selected-video {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px;
  background: #F1F5F9;
  border-radius: 8px;
}

.video-preview-thumb {
  width: 70px;
  height: 40px;
  border-radius: 6px;
  overflow: hidden;
  background: #1E293B;
  flex-shrink: 0;

  img {
    width: 100%;
    height: 100%;
    object-fit: cover;
  }
}

.video-preview-info {
  flex: 1;
  min-width: 0;
}

.video-name {
  font-size: 13px;
  font-weight: 500;
  color: #1E293B;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.video-meta {
  font-size: 11px;
  color: #94A3B8;
}

.change-video-btn {
  padding: 4px 10px;
  font-size: 11px;
  color: #64748B;
  border: none;
  background: transparent;
  cursor: pointer;
  text-decoration: underline;
  flex-shrink: 0;

  &:hover {
    color: #3B82F6;
  }
}

// 上传区域
.upload-zone {
  min-height: 160px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 2px dashed #E2E8F0;
  border-radius: 10px;
  background: #F8FAFC;
  transition: all 0.2s ease;

  &--dragover {
    border-color: #3B82F6;
    background: #EFF6FF;
  }
}

.file-input {
  display: none;
}

.upload-placeholder {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
}

.upload-icon {
  font-size: 28px;
  color: #94A3B8;
}

.upload-text {
  font-size: 13px;
  font-weight: 500;
  color: #1E293B;
}

.upload-hint {
  font-size: 11px;
  color: #94A3B8;
}

.select-file-btn {
  margin-top: 12px;
  padding: 6px 16px;
  font-size: 12px;
  font-weight: 500;
  color: #3B82F6;
  border: none;
  background: transparent;
  cursor: pointer;
  border: 1px solid #3B82F6;
  border-radius: 6px;
  transition: all 0.2s ease;

  &:hover {
    background: rgba(59, 130, 246, 0.1);
  }
}

.upload-preview {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  padding: 12px;
}

.preview-video-player {
  width: 100%;
  max-height: 140px;
  border-radius: 8px;
}

.upload-filename {
  font-size: 12px;
  color: #64748B;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  padding: 6px 10px;
  background: #F1F5F9;
  border-radius: 6px;
}

// 操作按钮区
.action-section {
  margin-top: 20px;
  padding-top: 16px;
  border-top: 1px solid #E2E8F0;
}

.action-btn {
  height: 44px;
  font-size: 15px;
  font-weight: 600;
  border-radius: 8px;

  &.ant-btn-primary {
    background: linear-gradient(135deg, #3B82F6 0%, #2563EB 100%);
    border: none;

    &:hover:not(:disabled) {
      box-shadow: 0 4px 12px rgba(59, 130, 246, 0.35);
    }

    &:disabled {
      background: #D1D5DB;
    }
  }
}

.completed-tip {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  padding: 12px 16px;
  background: #F0FDF4;
  border: 1px solid #86EFAC;
  border-radius: 8px;
  color: #166534;
  font-size: 14px;
  font-weight: 500;

  .reset-btn {
    padding: 4px 12px;
    font-size: 13px;
    color: #3B82F6;
    border: 1px solid #3B82F6;
    border-radius: 4px;
    background: transparent;
    cursor: pointer;
    transition: all 0.2s;

    &:hover {
      background: rgba(59, 130, 246, 0.1);
    }
  }
}

// 预览面板
.preview-card {
  position: sticky;
  top: 24px;
}

.preview-title {
  font-size: 16px;
  font-weight: 600;
  color: #1E293B;
  margin: 0 0 16px 0;
}

.preview-screen {
  aspect-ratio: 9/16;
  background: #1E293B;
  border-radius: 12px;
  margin-bottom: 20px;
  overflow: hidden;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;

  &::after {
    content: '预览画面不可用';
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(0, 0, 0, 0.6);
    color: #fff;
    font-size: 13px;
  }

  :deep(.result-panel) {
    height: 100%;
  }
}

.preview-meta {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 16px;
  background: #F8FAFC;
  border-radius: 8px;
}

.meta-row {
  display: flex;
  justify-content: space-between;
  font-size: 12px;
}

.meta-label {
  color: #64748B;
}

.meta-row .meta-value {
  font-weight: 600;
  color: #1E293B;
}

// 响应式
@media (max-width: 1024px) {
  .digital-human-page {
    flex-direction: column;
  }

  .config-panel {
    max-width: 100%;
    padding: 16px;
  }

  .preview-panel {
    width: 100%;
    border-left: none;
    border-top: 1px solid #E2E8F0;
    order: -1;
    padding: 16px;
  }

  .preview-card {
    position: static;
  }

  .preview-screen {
    min-height: 200px;
  }
}
</style>
