<template>
  <FullWidthLayout :show-padding="false">
    <div class="notion-page">
      <!-- 主内容区域 -->
      <div class="main-content">
        <!-- 左侧：视频模块 -->
        <section class="content-block">
          <div class="block-header">
            <span class="block-emoji">📹</span>
            <h3 class="block-title">视频素材</h3>
          </div>

          <!-- 视频来源选项 -->
          <div class="source-toggle">
            <button
              class="toggle-btn"
              :class="{ active: store.videoSource === 'upload' }"
              @click="store.selectUploadMode"
            >
              <CloudUploadOutlined />
              <span>上传视频</span>
            </button>
            <button
              class="toggle-btn"
              :class="{ active: store.videoSource === 'select' }"
              @click="store.selectLibraryMode"
            >
              <FolderOutlined />
              <span>素材库</span>
            </button>
          </div>

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

            <div v-if="!store.videoPreviewUrl" class="upload-empty" @click="triggerFileSelect">
              <div class="upload-icon-wrapper">
                <CloudUploadOutlined class="upload-icon" />
              </div>
              <div class="upload-text">点击上传或拖拽文件到此处</div>
              <div class="upload-hint">支持 MP4、MOV 格式，视频需大于 3 秒</div>
            </div>

            <div v-else class="upload-preview">
              <video
                :src="store.videoPreviewUrl"
                controls
                playsinline
                preload="metadata"
                class="preview-video"
              ></video>
              <button class="replace-btn" @click="clearVideo">
                <ReloadOutlined />
                <span>更换视频</span>
              </button>
            </div>
          </div>

          <!-- 已选视频预览（素材库） -->
          <div v-if="store.selectedVideo && store.videoSource === 'select'" class="library-preview">
            <video
              v-if="store.videoPreviewUrl"
              :src="store.videoPreviewUrl"
              controls
              playsinline
              preload="metadata"
              class="preview-video"
            ></video>
            <div class="video-meta">
              <div class="video-name" :title="store.selectedVideo.fileName">{{ store.selectedVideo.fileName }}</div>
              <div class="video-info">
                {{ formatDuration(store.selectedVideo.duration) }} · {{ formatFileSize(store.selectedVideo.fileSize) }}
              </div>
            </div>
            <button class="replace-btn" @click="clearVideo">
              <ReloadOutlined />
              <span>更换</span>
            </button>
          </div>

          <!-- 识别状态 -->
          <div v-if="store.videoStep !== 'idle'" class="process-status" :class="store.videoStep">
            <div v-if="store.videoStep === 'uploading'" class="status-row">
              <a-spin size="small" />
              <span>正在上传视频...</span>
            </div>
            <div v-else-if="store.videoStep === 'recognizing'" class="status-row">
              <a-spin size="small" />
              <span>正在识别人脸...</span>
            </div>
            <div v-else-if="store.videoStep === 'recognized'" class="status-row success">
              <CheckCircleOutlined />
              <span>识别成功 · 人脸时长 {{ formatDurationMs(store.faceDurationMs) }}</span>
            </div>
            <div v-else-if="store.videoStep === 'error'" class="status-row error">
              <ExclamationCircleOutlined />
              <span>{{ store.error }}</span>
              <button class="link-btn" @click="store.retry">重试</button>
            </div>
          </div>

          <!-- 生成按钮 - 放在左侧面板底部 -->
          <div class="generate-action">
            <!-- 成功状态 -->
            <div v-if="store.isDone" class="result-inline success">
              <CheckCircleFilled />
              <span>任务已提交</span>
              <button class="inline-btn" @click="store.reset">重新生成</button>
            </div>

            <!-- 错误状态 -->
            <div v-else-if="store.createStep === 'error'" class="result-inline error">
              <ExclamationCircleFilled />
              <span>{{ store.error }}</span>
              <button class="link-btn" @click="store.retry">重试</button>
            </div>

            <!-- 生成按钮 -->
            <button
              v-else
              class="generate-btn"
              :class="{ disabled: !store.canGenerate }"
              :disabled="!store.canGenerate"
              @click="store.createTask"
            >
              <div class="btn-glow"></div>
              <div class="btn-left">
                <template v-if="store.createStep === 'creating'">
                  <LoadingOutlined class="btn-spin" spin />
                  <span>正在创建...</span>
                </template>
                <template v-else>
                  <PlayCircleOutlined class="btn-icon" />
                  <span>生成视频</span>
                </template>
              </div>
              <div class="btn-right">
                <span class="cost-num">{{ estimatedPoints }}</span>
                <span class="cost-label">积分</span>
              </div>
            </button>
          </div>
        </section>

        <!-- 右侧：配音文案模块 -->
        <section class="content-block">
          <div class="block-header">
            <span class="block-emoji">🎙️</span>
            <h3 class="block-title">配音文案</h3>
          </div>

          <!-- 文案输入 -->
          <div class="input-section">
            <div class="label-row">
              <label class="input-label">播报文案</label>
              <button class="generate-text-btn" @click="openTextGeneratePopup">
                <EditOutlined />
                <span>AI 生成</span>
              </button>
            </div>
            <a-textarea
              v-model:value="store.text"
              :placeholder="placeholder"
              :rows="6"
              :maxlength="4000"
              :show-count="true"
              class="notion-textarea"
              :bordered="false"
            />
            <div class="input-footer">
              <span>{{ store.text?.length || 0 }} 字</span>
              <span v-if="store.faceDurationMs > 0">· 建议 {{ suggestedChars }} 字</span>
            </div>
          </div>

          <!-- 文案生成浮窗 -->
          <TextGeneratePopup
            v-model:visible="textGenerateVisible"
            @success="handleTextGenerated"
          />

          <!-- 音色选择 -->
          <div class="input-section">
            <label class="input-label">选择音色</label>
            <VoiceSelector
              :synth-text="store.text"
              :speech-rate="store.speechRate"
              @select="store.setVoice"
              @audio-generated="handleAudioGenerated"
            />
          </div>

          <!-- 语速调节 -->
          <div class="input-section">
            <label class="input-label">语速调节</label>
            <div class="rate-control">
              <a-slider
                v-model:value="store.speechRate"
                :min="0.5"
                :max="2.0"
                :step="0.1"
                :marks="rateMarks"
                class="rate-slider"
              />
              <span class="rate-value">{{ store.speechRate.toFixed(1) }}x</span>
            </div>
          </div>

          <!-- 时间轴对比 -->
          <TimelinePanel
            v-if="store.timeline"
            :face-duration-ms="store.timeline.videoDurationMs"
            :audio-duration-ms="store.timeline.audioDurationMs"
            :face-start-time="store.timeline.faceStartTime"
            :face-end-time="store.timeline.faceEndTime"
          />
        </section>
      </div>
    </div>

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

<script setup lang="ts">
import { ref, computed, onMounted } from 'vue'
import FullWidthLayout from '@/layouts/components/FullWidthLayout.vue'
import VideoSelector from '@/components/VideoSelector.vue'
import VoiceSelector from '@/components/VoiceSelector.vue'
import TimelinePanel from './components/TimelinePanel.vue'
import TextGeneratePopup from './components/TextGeneratePopup.vue'
import {
  CloudUploadOutlined,
  FolderOutlined,
  CheckCircleOutlined,
  ExclamationCircleOutlined,
  ReloadOutlined,
  PlayCircleOutlined,
  CheckCircleFilled,
  ExclamationCircleFilled,
  LoadingOutlined,
  EditOutlined,
} from '@ant-design/icons-vue'
import { useDigitalHumanStore } from './stores/useDigitalHumanStore'
import { useUserStore } from '@/stores/user'
import { usePointsConfigStore } from '@/stores/pointsConfig'
import { useVoiceCopyStore } from '@/stores/voiceCopy'
import { formatDuration, formatDurationMs, formatFileSize } from './utils/format'

const store = useDigitalHumanStore()
const userStore = useUserStore()
const pointsConfigStore = usePointsConfigStore()
const voiceStore = useVoiceCopyStore()

const dragOver = ref(false)
const fileInput = ref<HTMLInputElement | null>(null)
const textGenerateVisible = ref(false)

const estimatedPoints = computed(() => {
  const points = pointsConfigStore.getConsumePoints('kling')
  return points ?? 150
})

const suggestedChars = computed(() => {
  return Math.floor((store.faceDurationMs || 10000) / 1000 * 4)
})

const placeholder = computed(() =>
  store.faceDurationMs > 0
    ? `请输入播报文案，建议不超过 ${suggestedChars.value} 字以确保与视频匹配`
    : '请输入你想让角色说话的内容'
)

const rateMarks = {
  0.5: '0.5x',
  1.0: '1.0x',
  1.5: '1.5x',
  2.0: '2.0x',
}

function triggerFileSelect() {
  fileInput.value?.click()
}

function handleFileSelect(e: Event) {
  const file = (e.target as HTMLInputElement).files?.[0]
  if (file) {
    store.handleFileUpload(file)
  }
}

function handleDrop(e: DragEvent) {
  dragOver.value = false
  const file = e.dataTransfer?.files[0]
  if (file) {
    store.handleFileUpload(file)
  }
}

function clearVideo() {
  if (store.videoPreviewUrl?.startsWith('blob:')) {
    URL.revokeObjectURL(store.videoPreviewUrl)
  }
  store.videoFile = null
  store.selectedVideo = null
  store.videoPreviewUrl = ''
  store.videoSource = null
  store.resetProcess()
}

function handleAudioGenerated(data: { durationMs: number; audioBase64: string }) {
  if (store.timeline && data.durationMs > 0) {
    store.timeline.audioDurationMs = data.durationMs
  }
  if (data.audioBase64) {
    store.audioData = {
      audioBase64: data.audioBase64,
      format: 'mp3',
      durationMs: data.durationMs
    }
    store.audioStep = 'generated'
  }
}

function openTextGeneratePopup() {
  textGenerateVisible.value = true
}

function handleTextGenerated(text: string) {
  store.text = text
}

onMounted(async () => {
  await Promise.all([
    voiceStore.refresh(),
    userStore.fetchUserProfile(),
    pointsConfigStore.loadConfig(),
  ])
})
</script>

<style scoped lang="less">
// ========================================
// Notion + VoiceSelector 蓝紫主题
// ========================================

// Color Palette - 与 VoiceSelector 协调
@bg-page: #fafbfc;
@bg-block: #ffffff;
@text-primary: #1e293b;
@text-secondary: #64748b;
@text-tertiary: #94a3b8;
@border-light: rgba(59, 130, 246, 0.1);
@border-medium: rgba(59, 130, 246, 0.2);

// 蓝紫渐变主题色 (与 VoiceSelector 一致)
@accent-blue: #3b82f6;
@accent-purple: #8b5cf6;
@accent-gradient: linear-gradient(135deg, @accent-blue 0%, @accent-purple 100%);
@accent-green: #10b981;
@accent-red: #ef4444;
@accent-orange: #f59e0b;

// Shadows - 柔和蓝调
@shadow-sm: 0 1px 2px rgba(59, 130, 246, 0.04);
@shadow-md: 0 4px 12px rgba(59, 130, 246, 0.08);
@shadow-lg: 0 8px 24px rgba(59, 130, 246, 0.12);

// Typography
@font-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, 'Apple Color Emoji', Arial, sans-serif;

.notion-page {
  min-height: 100vh;
  background: @bg-page;
  padding: 48px 64px;
  max-width: 1400px;
  margin: 0 auto;

  @media (max-width: 1024px) {
    padding: 32px 24px;
  }
}

// Page Header
.page-header {
  margin-bottom: 40px;

  .header-icon {
    font-size: 56px;
    margin-bottom: 16px;
    line-height: 1;
  }

  .header-title {
    font-family: @font-sans;
    font-size: 40px;
    font-weight: 700;
    color: @text-primary;
    margin: 0 0 8px 0;
    letter-spacing: -0.5px;
    line-height: 1.2;
  }

  .header-desc {
    font-size: 16px;
    color: @text-secondary;
    margin: 0;
    line-height: 1.5;
  }
}

// Main Content Layout
.main-content {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 24px;
  margin-bottom: 32px;

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

// Content Block
.content-block {
  background: @bg-block;
  border-radius: 12px;
  padding: 24px;
  box-shadow: @shadow-md;
  border: 1px solid @border-light;
  transition: all 0.3s ease;
  display: flex;
  flex-direction: column;

  &:hover {
    box-shadow: @shadow-lg;
    border-color: rgba(59, 130, 246, 0.2);
  }
}

// Block Header
.block-header {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 20px;
  padding-bottom: 14px;
  border-bottom: 1px solid rgba(59, 130, 246, 0.08);

  .block-emoji {
    font-size: 20px;
    line-height: 1;
  }

  .block-title {
    font-size: 15px;
    font-weight: 600;
    color: @text-primary;
    margin: 0;
  }
}

// Source Toggle
.source-toggle {
  display: flex;
  gap: 8px;
  margin-bottom: 20px;
  background: @bg-page;
  padding: 4px;
  border-radius: 6px;
}

.toggle-btn {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 10px 16px;
  border: none;
  background: transparent;
  border-radius: 8px;
  font-size: 13px;
  font-weight: 500;
  color: @text-secondary;
  cursor: pointer;
  transition: all 0.2s ease;

  &:hover {
    color: @text-primary;
    background: rgba(59, 130, 246, 0.05);
  }

  &.active {
    background: @bg-block;
    color: @accent-blue;
    box-shadow: 0 2px 8px rgba(59, 130, 246, 0.12);
  }
}

// Upload Area
.upload-area {
  min-height: 200px;
  border: 1.5px dashed rgba(59, 130, 246, 0.2);
  border-radius: 10px;
  background: rgba(59, 130, 246, 0.02);
  transition: all 0.25s ease;

  &.dragover {
    border-color: @accent-blue;
    background: rgba(59, 130, 246, 0.06);
  }

  &.has-video {
    border-style: solid;
    border-color: rgba(59, 130, 246, 0.1);
    background: @bg-block;
  }
}

.hidden-input {
  display: none;
}

.upload-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 200px;
  cursor: pointer;
  padding: 24px;
}

.upload-icon-wrapper {
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: rgba(59, 130, 246, 0.08);
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 14px;
  transition: all 0.25s ease;

  .upload-icon {
    font-size: 24px;
    color: @accent-blue;
  }
}

.upload-empty:hover .upload-icon-wrapper {
  background: rgba(59, 130, 246, 0.12);
  transform: scale(1.05);
}

.upload-text {
  font-size: 15px;
  font-weight: 500;
  color: @text-primary;
  margin-bottom: 6px;
}

.upload-hint {
  font-size: 13px;
  color: @text-tertiary;
}

.upload-preview {
  padding: 16px;
}

.preview-video {
  width: 100%;
  max-height: 260px;
  border-radius: 4px;
  background: #191919;
}

.replace-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: 12px;
  padding: 8px 14px;
  font-size: 13px;
  font-weight: 500;
  color: @text-secondary;
  background: transparent;
  border: 1px solid rgba(59, 130, 246, 0.15);
  border-radius: 8px;
  cursor: pointer;
  transition: all 0.2s ease;

  &:hover {
    color: @accent-blue;
    border-color: @accent-blue;
    background: rgba(59, 130, 246, 0.05);
  }
}

// Library Video Preview
.library-preview {
  padding: 16px;
  background: rgba(59, 130, 246, 0.03);
  border-radius: 10px;
  border: 1px solid rgba(59, 130, 246, 0.1);

  .preview-video {
    width: 100%;
    max-height: 260px;
    border-radius: 4px;
    background: #191919;
  }

  .video-meta {
    margin-top: 12px;
  }

  .replace-btn {
    margin-top: 8px;
  }
}

.video-thumbnail {
  width: 120px;
  height: 68px;
  border-radius: 4px;
  overflow: hidden;
  background: #191919;
  flex-shrink: 0;

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

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

.video-name {
  font-size: 14px;
  font-weight: 500;
  color: @text-primary;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  margin-bottom: 4px;
  max-width: 180px;
}

.video-info {
  font-size: 12px;
  color: @text-tertiary;
}

// Process Status
.process-status {
  margin-top: 14px;
  padding: 12px 16px;
  background: rgba(59, 130, 246, 0.04);
  border-radius: 8px;

  &.recognized {
    background: rgba(16, 185, 129, 0.08);
  }

  &.error {
    background: rgba(239, 68, 68, 0.08);
  }
}

.status-row {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 13px;
  color: @text-secondary;

  &.success {
    color: @accent-green;
  }

  &.error {
    color: @accent-red;
  }
}

.link-btn {
  margin-left: auto;
  padding: 0;
  font-size: 13px;
  font-weight: 500;
  color: @accent-blue;
  background: none;
  border: none;
  cursor: pointer;

  &:hover {
    text-decoration: underline;
  }
}

// Input Section
.input-section {
  margin-bottom: 24px;
}

.input-label {
  display: block;
  font-size: 12px;
  font-weight: 600;
  color: @text-secondary;
  text-transform: uppercase;
  letter-spacing: 0.5px;
}

.label-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 10px;
}

.notion-textarea {
  width: 100%;

  :deep(.ant-input) {
    border: none;
    border-radius: 8px;
    font-size: 14px;
    line-height: 1.6;
    padding: 14px 16px;
    background: rgba(59, 130, 246, 0.03);
    color: @text-primary;

    &::placeholder {
      color: @text-tertiary;
    }

    &:focus {
      background: @bg-block;
      box-shadow: 0 0 0 1px rgba(59, 130, 246, 0.2);
    }
  }

  :deep(.ant-input-data-count) {
    color: @text-tertiary;
    font-size: 12px;
  }
}

.input-footer {
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: 12px;
  color: @text-tertiary;
  margin-top: 8px;
}

.generate-text-btn {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 4px 10px;
  background: transparent;
  border: 1px solid rgba(59, 130, 246, 0.2);
  border-radius: 6px;
  font-size: 12px;
  font-weight: 500;
  color: @accent-blue;
  cursor: pointer;
  transition: all 0.2s ease;

  &:hover {
    background: rgba(59, 130, 246, 0.06);
    border-color: rgba(59, 130, 246, 0.3);
  }
}

// Rate Control
.rate-control {
  display: flex;
  align-items: center;
  gap: 16px;
}

.rate-slider {
  flex: 1;

  :deep(.ant-slider-rail) {
    background: rgba(59, 130, 246, 0.1);
  }

  :deep(.ant-slider-track) {
    background: @accent-gradient;
  }

  :deep(.ant-slider-handle) {
    border-color: @accent-blue;

    &:hover, &:focus {
      border-color: @accent-blue;
      box-shadow: 0 0 0 4px rgba(59, 130, 246, 0.15);
    }
  }

  :deep(.ant-slider-mark-text) {
    font-size: 11px;
    color: @text-tertiary;
  }
}

.rate-value {
  font-size: 14px;
  font-weight: 600;
  color: @text-primary;
  min-width: 40px;
  text-align: right;
}

// 生成按钮 - 左右布局，右下角
.generate-action {
  margin-top: auto;
  padding-top: 16px;
  display: flex;
  justify-content: flex-end;
}

.result-banner {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 10px;
  padding: 10px 14px;
  border-radius: 8px;
  font-size: 13px;
  font-weight: 500;

  &.success {
    background: rgba(16, 185, 129, 0.08);
    color: @accent-green;
  }

  &.error {
    background: rgba(239, 68, 68, 0.08);
    color: @accent-red;
  }

  .banner-icon {
    font-size: 16px;
    flex-shrink: 0;
  }

  .banner-text {
    flex: 1;
    text-align: right;
  }

  .retry-btn {
    padding: 4px 12px;
    border-radius: 6px;
    border: 1px solid currentColor;
    background: transparent;
    color: inherit;
    font-size: 12px;
    font-weight: 500;
    cursor: pointer;
    transition: all 0.2s ease;
    display: flex;
    align-items: center;
    gap: 4px;

    &:hover {
      background: rgba(16, 185, 129, 0.1);
    }
  }
}

.generate-btn {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 14px;
  border: none;
  border-radius: 8px;
  background: @accent-gradient;
  color: white;
  cursor: pointer;
  overflow: hidden;
  transition: all 0.25s ease;
  box-shadow: 0 4px 16px rgba(59, 130, 246, 0.25);

  &:hover:not(.disabled) {
    transform: translateY(-1px);
    box-shadow: 0 6px 20px rgba(59, 130, 246, 0.35);
  }

  &:active:not(.disabled) {
    transform: translateY(0);
  }

  &.disabled {
    background: linear-gradient(135deg, #cbd5e1 0%, #94a3b8 100%);
    cursor: not-allowed;
    box-shadow: 0 2px 8px rgba(148, 163, 184, 0.25);
  }

  .btn-glow {
    position: absolute;
    top: 0;
    left: -100%;
    width: 100%;
    height: 100%;
    background: linear-gradient(
      90deg,
      transparent,
      rgba(255, 255, 255, 0.15),
      transparent
    );
    animation: glow-slide 3s ease-in-out infinite;
  }

  .btn-left {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 13px;
    font-weight: 600;
    position: relative;
    z-index: 1;
  }

  .btn-icon {
    font-size: 15px;
  }

  .btn-spin {
    font-size: 13px;
    animation: spin 1s linear infinite;
  }

  .btn-right {
    display: flex;
    align-items: baseline;
    gap: 2px;
    padding: 2px 8px;
    background: rgba(255, 255, 255, 0.15);
    border-radius: 10px;
    font-size: 10px;
    position: relative;
    z-index: 1;
  }

  .cost-num {
    font-size: 12px;
    font-weight: 700;
  }

  .cost-label {
    opacity: 0.9;
  }
}

@keyframes glow-slide {
  0% {
    left: -100%;
  }
  50%, 100% {
    left: 100%;
  }
}

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

.link-btn {
  padding: 0;
  font-size: 13px;
  font-weight: 500;
  color: inherit;
  background: none;
  border: none;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 2px;

  &:hover {
    opacity: 0.8;
  }
}
</style>
