<template>
  <div class="frame-capture">
    <!-- 上传 -->
    <div class="upload-section">
      <input type="file" accept="video/*" @change="handleVideoUpload" />
      <span v-if="videoFile">{{ videoFile.name }}</span>
    </div>

    <!-- 视频 -->
    <div class="video-wrapper">
      <video
        ref="videoRef"
        :src="videoUrl"
        controls
        @loadedmetadata="onVideoLoaded"
        @timeupdate="onTimeUpdate"
        @seeked="onSeeked"
      ></video>
    </div>

    <!-- 编辑器 -->
    <div v-if="videoLoaded" class="editor">
      <div class="timeline-container">
        <div class="timeline-header">
          <span>⏱ 当前：{{ formatTime(currentTime) }}</span>
          <span>总时长：{{ formatTime(videoDuration) }}</span>
          <span>分辨率：{{ videoWidth }} × {{ videoHeight }}</span>
        </div>

        <!-- ⭐ 时间轴轨道（包含帧缩略图） -->
        <div
          class="timeline-track"
          ref="trackRef"
          @mousedown="onTrackMouseDown"
          @touchstart="onTrackTouchStart"
        >
          <!-- 帧缩略图层 -->
          <div class="thumbnails-layer" ref="thumbnailsLayer">
            <!-- 由 JS 动态生成 canvas 填充 -->
          </div>

          <!-- 刻度 -->
          <div class="ticks">
            <span v-for="tick in ticks" :key="tick" class="tick" :style="{ left: tick + '%' }">|</span>
          </div>

          <!-- 进度填充 -->
          <div class="progress-fill" :style="{ width: pointerPos + '%' }"></div>

          <!-- 指针 -->
          <div
            class="pointer"
            :style="{ left: pointerPos + '%' }"
            @mousedown.stop="onPointerMouseDown"
            @touchstart.stop="onPointerTouchStart"
          >
            <div class="pointer-line"></div>
            <div class="pointer-circle">▼</div>
            <div class="pointer-tooltip">{{ formatTime(currentTime) }}</div>
          </div>

          <!-- 缩略图预览 -->
          <div v-if="showThumbnail" class="thumbnail-preview" :style="{ left: pointerPos + '%' }">
            <video ref="thumbVideo" :src="videoUrl" muted style="display:none;"></video>
            <canvas ref="thumbCanvas" width="160" height="90"></canvas>
          </div>
        </div>

        <!-- 控制按钮 -->
        <div class="actions">
          <button @click="captureFrame" class="btn-primary">🖼️ 截取当前帧</button>
          <button @click="captureFrameHQ" class="btn-secondary">⭐ 高清截图</button>
          <button @click="resetPointer" class="btn-reset">↺ 重置</button>
        </div>
      </div>

      <div v-if="status" class="status">{{ status }}</div>
    </div>

    <!-- 结果 -->
    <div v-if="singleImage" class="result-single">
      <h4>✅ 截图成功</h4>
      <img :src="singleImage" />
      <a :href="singleImage" download="frame.jpg" class="btn-download">📥 下载</a>
      <button @click="copyToClipboard" class="btn-copy">📋 复制</button>
    </div>
  </div>
</template>

<script setup>
import { ref, computed, onUnmounted, nextTick } from 'vue'

// --- 状态 ---
const videoRef = ref(null)
const thumbVideo = ref(null)
const thumbCanvas = ref(null)
const thumbnailsLayer = ref(null)
const trackRef = ref(null)
const videoFile = ref(null)
const videoUrl = ref('')
const videoLoaded = ref(false)
const videoDuration = ref(0)
const videoWidth = ref(0)
const videoHeight = ref(0)
const currentTime = ref(0)
const pointerPos = ref(0)
const isDragging = ref(false)
const showThumbnail = ref(false)
const status = ref('')
const singleImage = ref('')
const isGeneratingThumbnails = ref(false)

// 刻度
const ticks = computed(() => {
  const count = 20
  const result = []
  for (let i = 0; i <= count; i++) {
    result.push((i / count) * 100)
  }
  return result
})

// --- 视频处理 ---
const handleVideoUpload = (event) => {
  const file = event.target.files[0]
  if (!file) return

  videoFile.value = file
  videoUrl.value = URL.createObjectURL(file)
  videoLoaded.value = false
  singleImage.value = ''
  status.value = '📹 视频加载中...'
}

const onVideoLoaded = () => {
  if (!videoRef.value) return
  const video = videoRef.value
  videoDuration.value = video.duration
  videoWidth.value = video.videoWidth
  videoHeight.value = video.videoHeight
  currentTime.value = 0
  pointerPos.value = 0
  videoLoaded.value = true
  status.value = `✅ 视频已加载 (${videoWidth.value}×${videoHeight.value})`

  // ⭐ 生成帧缩略图
  nextTick(() => {
    generateThumbnails()
  })
}

// --- ⭐ 核心：生成帧缩略图 ---
const generateThumbnails = async () => {
  if (isGeneratingThumbnails.value) return
  isGeneratingThumbnails.value = true
  status.value = '🖼️ 正在生成帧缩略图...'

  const video = videoRef.value
  const container = thumbnailsLayer.value
  if (!video || !container) {
    isGeneratingThumbnails.value = false
    return
  }

  // 清空容器
  container.innerHTML = ''

  // 计算缩略图数量（根据轨道宽度，每 8px 一张）
  const trackWidth = trackRef.value?.clientWidth || 800
  const thumbWidth = 60 // 每张缩略图宽度
  const count = Math.min(Math.floor(trackWidth / thumbWidth), 60) // 最多 60 张
  const step = videoDuration.value / count

  // 创建 canvas 用于绘制缩略图
  const canvas = document.createElement('canvas')
  const ctx = canvas.getContext('2d')
  const thumbHeight = 56 // 与轨道高度一致
  canvas.width = thumbWidth
  canvas.height = thumbHeight

  // 存储所有缩略图数据
  const thumbPromises = []

  for (let i = 0; i < count; i++) {
    const time = step * i + step / 2 // 取每个区间的中间帧
    const promise = new Promise((resolve) => {
      const seekVideo = document.createElement('video')
      seekVideo.src = videoUrl.value
      seekVideo.muted = true
      seekVideo.currentTime = Math.min(time, videoDuration.value - 0.01)

      const onSeeked = () => {
        // 绘制当前帧到 canvas
        const scaleX = thumbWidth / video.videoWidth
        const scaleY = thumbHeight / video.videoHeight
        const scale = Math.min(scaleX, scaleY)
        const drawWidth = video.videoWidth * scale
        const drawHeight = video.videoHeight * scale
        const offsetX = (thumbWidth - drawWidth) / 2
        const offsetY = (thumbHeight - drawHeight) / 2

        ctx.clearRect(0, 0, thumbWidth, thumbHeight)
        ctx.drawImage(seekVideo, offsetX, offsetY, drawWidth, drawHeight)

        const dataUrl = canvas.toDataURL('image/jpeg', 0.7)
        seekVideo.removeEventListener('seeked', onSeeked)
        resolve({ index: i, dataUrl })
      }

      seekVideo.addEventListener('seeked', onSeeked)
      // 超时保护
      setTimeout(() => {
        seekVideo.removeEventListener('seeked', onSeeked)
        resolve({ index: i, dataUrl: null })
      }, 3000)
    })

    thumbPromises.push(promise)
  }

  // 等待所有缩略图生成完成
  const results = await Promise.all(thumbPromises)

  // 渲染缩略图到容器
  results.forEach((result) => {
    if (!result.dataUrl) return
    const img = document.createElement('img')
    img.src = result.dataUrl
    img.alt = `帧 ${result.index}`
    img.className = 'thumbnail-img'
    img.style.width = thumbWidth + 'px'
    img.style.height = thumbHeight + 'px'
    img.style.objectFit = 'cover'
    container.appendChild(img)
  })

  isGeneratingThumbnails.value = false
  status.value = `✅ 已生成 ${results.filter(r => r.dataUrl).length} 张缩略图`
}

// --- 时间轴拖拽（省略完整实现，保留核心）---
const getPosition = (e) => {
  if (!trackRef.value) return 0
  const rect = trackRef.value.getBoundingClientRect()
  const clientX = e.touches ? e.touches[0].clientX : e.clientX
  let pos = (clientX - rect.left) / rect.width
  return Math.max(0, Math.min(1, pos))
}

const updatePointer = (pos) => {
  const time = pos * videoDuration.value
  currentTime.value = Math.max(0, Math.min(time, videoDuration.value))
  pointerPos.value = pos * 100
  if (videoRef.value) {
    videoRef.value.currentTime = currentTime.value
  }
  updateThumbnail()
}

const onTrackMouseDown = (e) => {
  if (e.button !== 0) return
  const pos = getPosition(e)
  updatePointer(pos)
  isDragging.value = true
  showThumbnail.value = true
  document.addEventListener('mousemove', onTrackDrag)
  document.addEventListener('mouseup', onDragEnd)
}

const onTrackTouchStart = (e) => {
  e.preventDefault()
  const pos = getPosition(e)
  updatePointer(pos)
  isDragging.value = true
  showThumbnail.value = true
  document.addEventListener('touchmove', onTrackTouchDrag)
  document.addEventListener('touchend', onDragEnd)
}

const onTrackDrag = (e) => {
  const pos = getPosition(e)
  updatePointer(pos)
}

const onTrackTouchDrag = (e) => {
  e.preventDefault()
  const pos = getPosition(e)
  updatePointer(pos)
}

const onPointerMouseDown = (e) => {
  e.stopPropagation()
  isDragging.value = true
  showThumbnail.value = true
  document.addEventListener('mousemove', onTrackDrag)
  document.addEventListener('mouseup', onDragEnd)
}

const onPointerTouchStart = (e) => {
  e.preventDefault()
  e.stopPropagation()
  isDragging.value = true
  showThumbnail.value = true
  document.addEventListener('touchmove', onTrackTouchDrag)
  document.addEventListener('touchend', onDragEnd)
}

const onDragEnd = () => {
  isDragging.value = false
  showThumbnail.value = false
  document.removeEventListener('mousemove', onTrackDrag)
  document.removeEventListener('touchmove', onTrackTouchDrag)
  document.removeEventListener('mouseup', onDragEnd)
  document.removeEventListener('touchend', onDragEnd)
}

const onTimeUpdate = () => {
  if (!videoRef.value || isDragging.value) return
  currentTime.value = videoRef.value.currentTime
  pointerPos.value = (currentTime.value / videoDuration.value) * 100
}

const onSeeked = () => {
  if (!videoRef.value) return
  currentTime.value = videoRef.value.currentTime
  pointerPos.value = (currentTime.value / videoDuration.value) * 100
}

// --- 缩略图 ---
const updateThumbnail = () => {
  if (!thumbVideo.value || !thumbCanvas.value) return
  const video = thumbVideo.value
  const canvas = thumbCanvas.value
  const ctx = canvas.getContext('2d')

  video.currentTime = currentTime.value
  video.addEventListener('seeked', function onSeeked() {
    ctx.drawImage(video, 0, 0, canvas.width, canvas.height)
    video.removeEventListener('seeked', onSeeked)
  }, { once: true })
}

// --- 重置 ---
const resetPointer = () => {
  currentTime.value = 0
  pointerPos.value = 0
  if (videoRef.value) {
    videoRef.value.currentTime = 0
    videoRef.value.pause()
  }
  status.value = '已重置到开头'
}

// --- 截图 ---
const captureWithCanvas = (time, width, height, quality = 0.92) => {
  return new Promise((resolve) => {
    const video = videoRef.value
    if (!video) return resolve(null)
    if (video.readyState < 2) return resolve(null)

    const w = width || video.videoWidth
    const h = height || video.videoHeight
    const canvas = document.createElement('canvas')
    canvas.width = w
    canvas.height = h

    const ctx = canvas.getContext('2d')
    ctx.imageSmoothingEnabled = true
    ctx.imageSmoothingQuality = 'high'
    ctx.drawImage(video, 0, 0, w, h)

    const dataUrl = canvas.toDataURL('image/jpeg', quality)
    resolve(dataUrl)
  })
}

const captureFrame = async () => {
  if (!videoRef.value) return
  status.value = '🖼️ 截图中...'

  const video = videoRef.value
  video.currentTime = currentTime.value

  await new Promise((resolve) => {
    const onSeeked = () => {
      video.removeEventListener('seeked', onSeeked)
      resolve()
    }
    video.addEventListener('seeked', onSeeked)
    setTimeout(() => {
      video.removeEventListener('seeked', onSeeked)
      resolve()
    }, 2000)
  })

  const dataUrl = await captureWithCanvas(currentTime.value)
  if (dataUrl) {
    singleImage.value = dataUrl
    status.value = '✅ 截图成功！'
  } else {
    status.value = '❌ 截图失败，请重试'
  }
}

const captureFrameHQ = async () => {
  if (!videoRef.value) return
  status.value = '⭐ 高清截图中...'

  const video = videoRef.value
  video.currentTime = currentTime.value

  await new Promise((resolve) => {
    const onSeeked = () => {
      video.removeEventListener('seeked', onSeeked)
      resolve()
    }
    video.addEventListener('seeked', onSeeked)
    setTimeout(() => {
      video.removeEventListener('seeked', onSeeked)
      resolve()
    }, 2000)
  })

  const w = videoWidth.value * 2
  const h = videoHeight.value * 2
  const dataUrl = await captureWithCanvas(currentTime.value, w, h, 0.95)

  if (dataUrl) {
    singleImage.value = dataUrl
    status.value = '✅ 高清截图成功！'
  } else {
    status.value = '❌ 高清截图失败'
  }
}

const copyToClipboard = async () => {
  try {
    const response = await fetch(singleImage.value)
    const blob = await response.blob()
    await navigator.clipboard.write([
      new ClipboardItem({
        [blob.type]: blob
      })
    ])
    status.value = '✅ 图片已复制到剪贴板'
  } catch (error) {
    status.value = '❌ 复制失败: ' + error.message
  }
}

const formatTime = (seconds) => {
  if (!seconds || seconds < 0) return '00:00:00'
  const s = Math.floor(seconds)
  const m = Math.floor(s / 60)
  const h = Math.floor(m / 60)
  const remainS = s % 60
  const remainM = m % 60
  if (h > 0) {
    return `${h}:${String(remainM).padStart(2, '0')}:${String(remainS).padStart(2, '0')}`
  }
  return `${String(remainM).padStart(2, '0')}:${String(remainS).padStart(2, '0')}`
}

// --- 生命周期 ---
onUnmounted(() => {
  document.removeEventListener('mousemove', onTrackDrag)
  document.removeEventListener('touchmove', onTrackTouchDrag)
  document.removeEventListener('mouseup', onDragEnd)
  document.removeEventListener('touchend', onDragEnd)
})
</script>

<style scoped>
.frame-capture {
  max-width: 860px;
  margin: 0 auto;
  padding: 24px;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}

.upload-section {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 16px;
  background: #f5f7fa;
  border-radius: 8px;
  margin-bottom: 16px;
}

.video-wrapper {
  background: #000;
  border-radius: 12px;
  overflow: hidden;
}
.video-wrapper video {
  width: 100%;
  display: block;
  min-height: 200px;
  background: #000;
}

.editor {
  margin-top: 12px;
}

.timeline-container {
  padding: 16px 12px;
  background: white;
  border-radius: 8px;
  border: 1px solid #e5e7eb;
}

.timeline-header {
  display: flex;
  justify-content: space-between;
  font-family: monospace;
  font-size: 13px;
  color: #666;
  margin-bottom: 10px;
  flex-wrap: wrap;
  gap: 4px;
}

/* ⭐ 时间轴轨道 - 包含缩略图 */
.timeline-track {
  position: relative;
  height: 56px;
  background: #1a1a2e;
  border-radius: 6px;
  cursor: pointer;
  user-select: none;
  overflow: hidden;
}

/* 缩略图层 */
.thumbnails-layer {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  display: flex;
  z-index: 1;
  overflow: hidden;
  border-radius: 6px;
}

.thumbnail-img {
  flex-shrink: 0;
  display: block;
  object-fit: cover;
}

/* 刻度 - 在缩略图上方 */
.ticks {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 2;
  pointer-events: none;
}
.tick {
  position: absolute;
  top: 0;
  color: rgba(255, 255, 255, 0.4);
  font-size: 9px;
  transform: translateX(-50%);
  pointer-events: none;
}

/* 进度填充 - 在半透明层上 */
.progress-fill {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  background: rgba(74, 108, 247, 0.3);
  border-radius: 6px;
  pointer-events: none;
  z-index: 3;
  transition: width 0.05s linear;
}

/* 指针 */
.pointer {
  position: absolute;
  top: -8px;
  width: 20px;
  height: calc(100% + 16px);
  cursor: ew-resize;
  z-index: 10;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
}

.pointer-line {
  position: absolute;
  top: 0;
  width: 3px;
  height: 100%;
  background: #ff6b6b;
  border-radius: 2px;
  box-shadow: 0 0 12px rgba(255, 107, 107, 0.6);
}

.pointer-circle {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  font-size: 12px;
  color: #ff6b6b;
  background: white;
  border-radius: 50%;
  width: 28px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 2px 12px rgba(255, 107, 107, 0.5);
  border: 2px solid #ff6b6b;
}

.pointer-tooltip {
  position: absolute;
  bottom: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%);
  background: #1e293b;
  color: white;
  padding: 2px 10px;
  border-radius: 4px;
  font-size: 12px;
  font-family: monospace;
  white-space: nowrap;
  opacity: 0;
  transition: opacity 0.2s;
  pointer-events: none;
}
.pointer:hover .pointer-tooltip,
.is-dragging .pointer-tooltip {
  opacity: 1;
}

/* 缩略图预览（悬浮大图） */
.thumbnail-preview {
  position: absolute;
  bottom: calc(100% + 20px);
  transform: translateX(-50%);
  background: white;
  border-radius: 8px;
  padding: 4px;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
  border: 2px solid #ff6b6b;
  z-index: 20;
}
.thumbnail-preview canvas {
  display: block;
  border-radius: 4px;
}

.actions {
  display: flex;
  gap: 10px;
  margin-top: 14px;
  flex-wrap: wrap;
}

.actions button {
  padding: 8px 18px;
  border: none;
  border-radius: 8px;
  font-size: 14px;
  cursor: pointer;
  transition: all 0.2s;
}

.btn-primary {
  background: #4a6cf7;
  color: white;
}
.btn-primary:hover {
  background: #3a5cd9;
}

.btn-secondary {
  background: #8b5cf6;
  color: white;
}
.btn-secondary:hover {
  background: #7c3aed;
}

.btn-reset {
  background: #e5e7eb;
  color: #333;
}
.btn-reset:hover {
  background: #d1d5db;
}

.status {
  margin-top: 12px;
  padding: 8px 16px;
  background: #eff6ff;
  border-radius: 6px;
  font-size: 14px;
  color: #1e40af;
}

.result-single {
  margin-top: 16px;
  padding: 20px;
  background: #f0f7ff;
  border-radius: 12px;
  border: 1px solid #bfdbfe;
  text-align: center;
}
.result-single img {
  max-width: 100%;
  max-height: 400px;
  border-radius: 8px;
}

.btn-download {
  display: inline-block;
  margin-top: 12px;
  padding: 8px 20px;
  background: #22c55e;
  color: white;
  border-radius: 6px;
  text-decoration: none;
  font-size: 14px;
  border: none;
  cursor: pointer;
}
.btn-download:hover {
  background: #16a34a;
}

.btn-copy {
  margin-top: 12px;
  margin-left: 10px;
  padding: 8px 20px;
  background: #4a6cf7;
  color: white;
  border: none;
  border-radius: 6px;
  font-size: 14px;
  cursor: pointer;
}
.btn-copy:hover {
  background: #3a5cd9;
}
</style>