<template>
  <div>
    <!-- 隐藏 video：仅用于读取时长，不展示 -->
    <video ref="videoRef" :src="videoUrl" preload="metadata" @loadedmetadata="onLoaded" @error="onError" style="display: none"></video>

    <!-- 时间轴 + 双手柄 -->
    <div v-if="videoLoaded" class="p-16 bg-fff round-8">
      <div class="px-10 py-14 bg-000 flex-center gap-30 round-8">
        <div class="analog-btn flex-center gap-4 px-10 py-6 pointer"><SvgIcon name="close" :size="18" color="#fff" /></div>
        <div class="relative h-48 bg-111 round-6 pointer flex-1 timeline-track" ref="trackRef" @click="onTrackClick">
          <div class="absolute top-0 h-full z-2 flex-center color-fff range-selected" :style="{ left: leftPos + '%', width: rightPos - leftPos + '%' }">
            {{ formatTime(endTime - startTime) }}s
          </div>
          <div
            class="absolute top-0 w-8 h-48 flex-center flex-col handle"
            :style="{ left: leftPos + '%' }"
            @mousedown.stop.prevent="startDrag('left')"
            @touchstart.stop.prevent="startDrag('left')"
          >
            <div class="w-8 h-full bg-fff flex-center color-fff fs-16 fw-bold handle-grip grip-left"></div>
          </div>
          <div
            class="absolute top-0 w-8 h-48 flex-center flex-col handle"
            :style="{ left: rightPos + '%' }"
            @mousedown.stop.prevent="startDrag('right')"
            @touchstart.stop.prevent="startDrag('right')"
          >
            <div class="w-8 h-full bg-fff flex-center color-fff fs-16 fw-bold handle-grip grip-right"></div>
          </div>
        </div>
        <ElButton class="bg-444 color-fff border-none btn-hover">确定</ElButton>
      </div>

      <div class="cut-bar">
        <span v-if="ffmpegReady" class="badge success">FFmpeg 就绪</span>
        <span v-else-if="ffmpegLoading" class="badge loading">FFmpeg 加载中...</span>
        <span v-else class="badge error">FFmpeg 未就绪</span>
        <button class="btn-cut" @click="doCut" :disabled="isProcessing || ffmpegLoading">
          {{ ffmpegLoading ? '加载 FFmpeg 中...' : isProcessing ? '裁剪中...' : '✂️ 裁剪视频' }}
        </button>
      </div>

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

    <!-- 裁剪结果 -->
    <div v-if="outputUrl" class="result">
      <h4>✅ 裁剪完成</h4>
      <video :src="outputUrl" controls class="result-video"></video>
      <div class="result-actions">
        <a :href="outputUrl" :download="outputName" class="btn-download">📥 下载视频</a>
        <button @click="resetOutput" class="btn-clear">清除结果</button>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, computed, onUnmounted } from 'vue';
import { toBlobURL, fetchFile } from '@ffmpeg/util';
import SvgIcon from '@/components/SvgIcon/SvgIcon.vue';

// --- 已知视频地址（public 目录下的文件用绝对路径引用） ---
const videoUrl = ref('/public/aaa.mp4');

// --- DOM 引用 ---
const videoRef = ref(null);
const trackRef = ref(null);

// --- 视频状态 ---
const videoLoaded = ref(false);
const videoDuration = ref(0);

// --- 时间轴双手柄 ---
const leftPos = ref(0);
const rightPos = ref(100);
const startTime = computed(() => (leftPos.value / 100) * videoDuration.value);
const endTime = computed(() => (rightPos.value / 100) * videoDuration.value);

let draggingHandle = null;

// --- FFmpeg（自定义 classic worker，绕过 @ffmpeg/ffmpeg 的 module worker 问题） ---
const ffmpegReady = ref(false);
const ffmpegLoading = ref(false);

// Worker 通信层
let worker = null;
let msgIdCounter = 0;
const pending = new Map(); // id → { resolve, reject }

const sendToWorker = (type, data, transfer = []) => {
  return new Promise((resolve, reject) => {
    const id = msgIdCounter++;
    pending.set(id, { resolve, reject });
    worker.postMessage({ id, type, data }, transfer);
  });
};

const onWorkerMessage = (e) => {
  const { id, type, data } = e.data;
  // LOG / PROGRESS 没有配对的 id（是 worker 主动推送的）
  if (type === 'LOG') {
    console.log('[FFmpeg]', data.message);
    return;
  }
  if (type === 'PROGRESS') {
    if (data.progress >= 0 && data.progress <= 1) {
      console.log('[FFmpeg] progress:', Math.round(data.progress * 100) + '%');
    }
    return;
  }
  if (type === 'ERROR') {
    const p = pending.get(id);
    if (p) {
      p.reject(new Error(data));
      pending.delete(id);
    }
    return;
  }
  // 正常响应
  const p = pending.get(id);
  if (p) {
    p.resolve(data);
    pending.delete(id);
  }
};

// --- 裁剪 ---
const isProcessing = ref(false);
const status = ref('');
const outputUrl = ref('');
const outputName = ref('trimmed.mp4');

// ==================== 视频元数据 ====================

const onLoaded = () => {
  if (!videoRef.value) return;
  videoDuration.value = videoRef.value.duration;
  leftPos.value = 0;
  rightPos.value = 100;
  videoLoaded.value = true;
};

const onError = () => {
  videoLoaded.value = false;
  status.value = '❌ 视频加载失败，请检查视频地址';
};

// ==================== 双手柄拖拽 ====================

const getPosFromEvent = (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) * 100;
  return Math.max(0, Math.min(100, pos));
};

const startDrag = (handle) => {
  draggingHandle = handle;
  document.addEventListener('mousemove', onDragMove);
  document.addEventListener('mouseup', stopDrag);
  document.addEventListener('touchmove', onDragMove, { passive: false });
  document.addEventListener('touchend', stopDrag);
};

const onDragMove = (e) => {
  if (!draggingHandle) return;
  if (e.touches) e.preventDefault();
  const pos = getPosFromEvent(e);
  if (draggingHandle === 'left') {
    leftPos.value = Math.min(pos, rightPos.value - 1);
  } else {
    rightPos.value = Math.max(pos, leftPos.value + 1);
  }
};

const stopDrag = () => {
  draggingHandle = null;
  document.removeEventListener('mousemove', onDragMove);
  document.removeEventListener('mouseup', stopDrag);
  document.removeEventListener('touchmove', onDragMove);
  document.removeEventListener('touchend', stopDrag);
};

const onTrackClick = (e) => {
  if (e.target.closest('.handle')) return;
  const pos = getPosFromEvent(e);
  const distLeft = Math.abs(pos - leftPos.value);
  const distRight = Math.abs(pos - rightPos.value);
  if (distLeft < distRight) {
    leftPos.value = Math.min(pos, rightPos.value - 1);
  } else {
    rightPos.value = Math.max(pos, leftPos.value + 1);
  }
};

// ==================== FFmpeg 初始化（懒加载） ====================

const loadFFmpeg = async () => {
  if (ffmpegReady.value || ffmpegLoading.value) return;

  ffmpegLoading.value = true;
  status.value = '⏳ 正在加载 FFmpeg 引擎（约 32MB，首次较慢）...';
  try {
    // 1. 创建 classic worker（不用 type:module，importScripts 可用）
    console.log('[FFmpeg] 创建 worker...');
    worker = new Worker('/ffmpeg/ffmpeg-worker.js');
    worker.onmessage = onWorkerMessage;
    worker.onerror = (err) => {
      console.error('[FFmpeg] worker error:', err);
      // reject 所有 pending
      for (const [, p] of pending) p.reject(new Error('Worker error: ' + err.message));
      pending.clear();
    };

    // 2. 用 toBlobURL 把本地 UMD core + wasm 转成同源 blob URL
    //    classic worker 的 importScripts 加载 blob URL 没有跨域问题
    console.log('[FFmpeg] 下载 core (UMD)...');
    const coreURL = await toBlobURL('/ffmpeg/ffmpeg-core-umd.js', 'text/javascript');
    console.log('[FFmpeg] core 完成，下载 wasm...');
    const wasmURL = await toBlobURL('/ffmpeg/ffmpeg-core.wasm', 'application/wasm');
    console.log('[FFmpeg] wasm 完成，发送 LOAD 到 worker...');

    // 3. 发送 LOAD 指令，worker 内部 importScripts + createFFmpegCore
    await sendToWorker('LOAD', { coreURL, wasmURL });

    console.log('[FFmpeg] 初始化完成');
    ffmpegReady.value = true;
    ffmpegLoading.value = false;
    status.value = '✅ FFmpeg 就绪';
  } catch (err) {
    console.error('FFmpeg 加载失败:', err);
    ffmpegLoading.value = false;
    status.value = '❌ FFmpeg 加载失败: ' + (err?.message || err);
    if (worker) {
      worker.terminate();
      worker = null;
    }
  }
};

// ==================== 裁剪视频 ====================

const doCut = async () => {
  if (isProcessing.value) return;
  if (endTime.value - startTime.value < 0.1) {
    status.value = '❌ 裁剪范围太小';
    return;
  }

  // 懒加载：首次点击裁剪时才加载 FFmpeg
  if (!ffmpegReady.value) {
    await loadFFmpeg();
    if (!ffmpegReady.value) return;
  }

  isProcessing.value = true;
  outputUrl.value = '';
  status.value = '⏳ 裁剪中...';

  const inputName = 'input.mp4';
  const outputNameInner = 'output.mp4';
  const ss = startTime.value.toFixed(3);
  const duration = (endTime.value - startTime.value).toFixed(3);

  try {
    // fetchFile 把视频 URL fetch 成 Uint8Array
    const fileData = await fetchFile(videoUrl.value);
    // 写入虚拟文件系统（transfer buffer 提升性能）
    await sendToWorker('WRITE_FILE', { path: inputName, data: fileData }, [fileData.buffer]);

    // 执行裁剪：-ss 放 -i 之后做精确 seek，重编码保证帧级精度
    // （-c copy 只能从关键帧切，关键帧不在左边手柄位置时左边手柄会失效）
    await sendToWorker('EXEC', {
      args: [
        '-i',
        inputName,
        '-ss',
        ss,
        '-t',
        duration,
        '-c:v',
        'libx264',
        '-preset',
        'ultrafast',
        '-crf',
        '28',
        '-c:a',
        'aac',
        '-b:a',
        '128k',
        '-avoid_negative_ts',
        'make_zero',
        outputNameInner,
      ],
    });

    // 读回结果
    const data = await sendToWorker('READ_FILE', { path: outputNameInner });
    const blob = new Blob([data.buffer], { type: 'video/mp4' });
    outputUrl.value = URL.createObjectURL(blob);
    outputName.value = `trimmed_${ss.replace('.', '_')}.mp4`;

    // 清理虚拟文件系统
    try {
      await sendToWorker('DELETE_FILE', { path: inputName });
      await sendToWorker('DELETE_FILE', { path: outputNameInner });
    } catch (e) {}

    status.value = '✅ 裁剪完成！';
  } catch (err) {
    console.error('裁剪失败:', err);
    status.value = '❌ 裁剪失败: ' + (err?.message || err);
  } finally {
    isProcessing.value = false;
  }
};

const resetOutput = () => {
  if (outputUrl.value) URL.revokeObjectURL(outputUrl.value);
  outputUrl.value = '';
  status.value = '';
};

// ==================== 工具函数 ====================

const formatTime = (seconds) => {
  if (!seconds || seconds < 0) return '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(() => {
  stopDrag();
  if (outputUrl.value) URL.revokeObjectURL(outputUrl.value);
  if (worker) {
    worker.terminate();
    worker = null;
  }
});
</script>

<style scoped lang="scss">
/* 时间轴轨道 */
.timeline-track {
  user-select: none;
  overflow: visible;
}

.range-selected {
  background: rgba(0, 0, 0, 0.25);
  border-top: 1px solid #fff;
  border-bottom: 1px solid #fff;
  pointer-events: none;
  border-radius: 6px 0 0 6px;
}

/* 手柄 */
.handle {
  cursor: ew-resize;
  z-index: 10;

}

.handle-grip {
  box-shadow: 0 2px 8px rgba(74, 108, 247, 0.5);
  transition: background 0.2s;
  &.grip-left {
    border-radius: 4px 0 0 4px;
  }
  &.grip-right {
    border-radius: 0 4px 4px 0;
  }
}
.btn-hover {
  &:hover {
    opacity: 0.8;
    color: #fff;
    background: #444;
  }
}
</style>

<style lang="scss" scoped>
/* 播放器 */
.video-player {
  position: relative;
  width: 100%;
  height: 0;
  padding-bottom: 56.25%; /* 16:9 */
  background: #000;
  overflow: hidden;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.5);
  video {
    position: absolute;
    top: 0;
  }
}

.handle:hover .handle-grip {
  background: #ffffff;
}

.handle-time {
  position: absolute;
  bottom: calc(100% + 6px);
  left: 50%;
  transform: translateX(-50%);
  background: #1e293b;
  color: white;
  padding: 2px 8px;
  border-radius: 4px;
  font-size: 11px;
  font-family: monospace;
  white-space: nowrap;
  pointer-events: none;
}

/* 裁剪栏 */
.cut-bar {
  display: flex;
  align-items: center;
  gap: 12px;
}

.btn-cut {
  margin-left: auto;
  padding: 10px 24px;
  border: none;
  border-radius: 8px;
  background: #4a6cf7;
  color: white;
  font-size: 15px;
  cursor: pointer;
  transition: all 0.2s;
}

.btn-cut:hover:not(:disabled) {
  background: #3a5cd9;
}

.btn-cut:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.badge {
  padding: 2px 12px;
  border-radius: 12px;
  font-size: 13px;
}
.badge.success {
  background: #dcfce7;
  color: #166534;
}
.badge.loading {
  background: #fef3c7;
  color: #92400e;
}
.badge.error {
  background: #fee2e2;
  color: #991b1b;
}

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

/* 结果 */
.result {
  margin-top: 16px;
  padding: 20px;
  background: #f0f7ff;
  border-radius: 12px;
  border: 1px solid #bfdbfe;
}

.result h4 {
  margin: 0 0 16px 0;
  color: #1e40af;
}

.result-video {
  width: 100%;
  border-radius: 8px;
  margin-bottom: 12px;
}

.result-actions {
  display: flex;
  gap: 10px;
}

.btn-download {
  display: inline-block;
  padding: 8px 20px;
  background: #22c55e;
  color: white;
  border-radius: 6px;
  text-decoration: none;
  font-size: 14px;
}

.btn-clear {
  padding: 8px 20px;
  background: #e5e7eb;
  color: #333;
  border: none;
  border-radius: 6px;
  font-size: 14px;
  cursor: pointer;
}

.analog-btn {
  &:hover {
    opacity: 0.8;
  }
}
</style>
