<template>
  <div class="realsense-viewer">
    <el-row type="flex" class="height-full">
      <el-col :span="4" class="control-panel" style="border-right: 10px solid rgb(40, 50, 60);">
        <div class="controls">
          <el-form :model="form">
            <el-form-item label="深度图像">
              <el-switch v-model="form.stereoModule"></el-switch>
            </el-form-item>
            <el-form-item label="彩色图像">
              <el-switch v-model="form.rgbCamera"></el-switch>
            </el-form-item>
          </el-form>
        </div>
      </el-col>
      <el-col :span="20" class="video-panel" v-if="form.stereoModule || form.rgbCamera">
        <div v-if="form.stereoModule && form.rgbCamera" class="stream-container">
          <div class="stream-item">
            <div class="stream-wrapper">
              <video ref="depthVideo"  autoplay muted playsinline></video>
              <video ref="depthVideoBuffer"  autoplay muted playsinline style="display: none;"></video>
            </div>
          </div>
          <div class="stream-item">
            <div class="stream-wrapper">
              <video ref="colorVideo"  autoplay muted playsinline></video>
              <video ref="colorVideoBuffer"  autoplay muted playsinline style="display: none;"></video>
            </div>
          </div>
        </div>
        <div v-else class="single-stream-container">
          <div v-if="form.stereoModule" class="stream-wrapper">
            <video ref="depthVideo" width="640" height="480" autoplay muted playsinline></video>
            <video ref="depthVideoBuffer" width="640" height="480" autoplay muted playsinline style="display: none;"></video>
          </div>
          <div v-if="form.rgbCamera" class="stream-wrapper">
            <video ref="colorVideo" width="640" height="480" autoplay muted playsinline></video>
            <video ref="colorVideoBuffer" width="640" height="480" autoplay muted playsinline style="display: none;"></video>
          </div>
        </div>
      </el-col>
      <el-col v-else :span="20" style="align-self: center;">
        <el-empty description="请选择模式" />
      </el-col>
    </el-row>
  </div>
</template>

<script setup>
import { inject, reactive, toRefs, watch, onMounted, onUnmounted, ref, nextTick } from 'vue';
import { getRegister } from "@/api/device/register";
import { useRoute } from "vue-router";
import { debounce } from 'lodash'; // 引入 lodash 的防抖函数

// 1. 定义 props
const props = defineProps({
  initialDeviceId: { // 示例 prop，用于从弹窗接收cameraId
    type: String,
    default: null,
  },
  initialTerminalId: { // 示例 prop，用于从弹窗接收 terminalId
    type: String,
    default: null,
  },
});

const socket = inject('ws');
const route = useRoute();
const data = reactive({
  form: {
    stereoModule: false,
    rgbCamera: false,
  },
  terminalId: null,
  cameraId: null,
  type: 'camera',
  callbacks: {},
});
const { form } = toRefs(data);
const depthVideo = ref(null);
const depthVideoBuffer = ref(null);
const colorVideo = ref(null);
const colorVideoBuffer = ref(null);
const blobUrls = ref([]);
const frameData = reactive({
  getRGBImageStream: { count: 0, lastTime: 0 },
  getDepthImageStream: { count: 0, lastTime: 0 },
});

function renderVideo(mainRef, bufferRef, data, channel, imageType) {
  const mainVideo = mainRef.value;
  const bufferVideo = bufferRef.value;
  if (!mainVideo || !bufferVideo) {
    console.error(`视频元素未找到 (${imageType}): 通道: ${channel}`);
    return;
  }

  const start = performance.now();
  try {
    if (typeof data === 'string') {
      const newSrc = data.startsWith('blob:') ? data : `data:video/mp4;base64,${data}`;
      
      // 先加载到缓冲视频元素
      bufferVideo.src = newSrc;
      bufferVideo.onloadeddata = () => {
        // 缓冲视频加载完成后，切换到主视频
        if (mainVideo.src && mainVideo.src.startsWith('blob:')) {
          URL.revokeObjectURL(mainVideo.src);
          blobUrls.value = blobUrls.value.filter(url => url !== mainVideo.src);
        }
        mainVideo.src = bufferVideo.src;
        blobUrls.value.push(newSrc);
        bufferVideo.src = ''; // 清空缓冲视频源
      };

      frameData[imageType].count++;
      const currentTime = performance.now();
      if (frameData[imageType].lastTime && currentTime - frameData[imageType].lastTime >= 1000) {
        const fps = frameData[imageType].count * 1000 / (currentTime - frameData[imageType].lastTime);
        console.log(`渲染帧率 (${imageType}): ${fps.toFixed(2)} fps, 通道: ${channel}`);
        frameData[imageType].count = 0;
        frameData[imageType].lastTime = currentTime;
      } else if (!frameData[imageType].lastTime) {
        frameData[imageType].lastTime = currentTime;
      }
      console.log(`视频渲染耗时 (${imageType}): ${performance.now() - start}ms, 通道: ${channel}`);
      if (performance.memory) {
        console.log('当前内存使用:', {
          usedJSHeapSize: (performance.memory.usedJSHeapSize / 1024 / 1024).toFixed(2) + ' MB',
          totalJSHeapSize: (performance.memory.totalJSHeapSize / 1024 / 1024).toFixed(2) + ' MB',
        });
      }
    } else {
      console.error(`未知 payload 类型 (${imageType}):`, typeof data, '通道:', channel);
    }
  } catch (err) {
    console.error(`视频渲染失败 (${imageType}):`, err, '通道:', channel);
  }
}

// 防抖订阅函数
const subscribeDebounced = debounce(async (sub, terminalId, method) => {
  if (!socket || !terminalId || !data.cameraId) {
    console.warn(`订阅失败: socket=${!!socket}, terminalId=${terminalId}, cameraId=${data.cameraId}, method=${method}`);
    return;
  }
  const channel = `edgeCameraServiceImpl/${method}/${terminalId}/${data.cameraId}`;
  console.log(sub ? '订阅' : '取消订阅', channel);
  socket.send({
    type: 'channel_subscription',
    action: sub ? 'subscribe' : 'unsubscribe',
    channel,
  });

  if (sub) {
    await nextTick();
    const mainRef = method === 'getRGBImageStream' ? colorVideo : depthVideo;
    const bufferRef = method === 'getRGBImageStream' ? colorVideoBuffer : depthVideoBuffer;
    if (!mainRef.value || !bufferRef.value) {
      console.error(`视频元素未找到: ${method}, 通道: ${channel}`);
      return;
    }

    // 清理旧回调
    if (data.callbacks[channel]) {
      socket.off(channel, data.callbacks[channel]);
      console.log('清理旧回调:', channel);
    }

    const callback = (data) => {
      if (data !== '500') {
        requestAnimationFrame(() => renderVideo(mainRef, bufferRef, data, channel, method));
      } else {
        // 错误处理：取消订阅后重新订阅
        subscribeDebounced(false, terminalId, method);
        subscribeDebounced(true, terminalId, method);
      }
    };
    socket.on(channel, callback);
    data.callbacks[channel] = callback;
    console.log('注册新回调:', channel);
  } else {
    if (data.callbacks[channel]) {
      socket.off(channel, data.callbacks[channel]);
      delete data.callbacks[channel];
      console.log('清理回调:', channel);
    }
  }
}, 300); // 300ms 防抖延迟

// 监听开关变化
watch(() => data.form.stereoModule, async (newVal) => {
  if (!data.terminalId || !data.cameraId) return;
  await nextTick();
  subscribeDebounced(newVal, data.terminalId, 'getDepthImageStream');
});

watch(() => data.form.rgbCamera, async (newVal) => {
  if (!data.terminalId || !data.cameraId) return;
  await nextTick();
  subscribeDebounced(newVal, data.terminalId, 'getRGBImageStream');
});

// 2. 使用 watchEffect 来响应 props 和路由的变化
watchEffect(() => {
  let deviceId = null;
  // 优先使用 props 中的值（如果弹窗传入了）
  if (props.initialDeviceId) {
    deviceId = props.initialDeviceId;
  }
  // 如果 props 没有传入，再从路由获取（仅当cameraId和terminalId都还没设置时）
  // 注意：这里需要根据你实际从路由获取参数的逻辑来调整
  // 假设 route.path.split("/")[3] 是cameraId
  if (!props.initialDeviceId && route.path.split("/")[3]) {
    deviceId = route.path.split("/")[3];
    // 调用 getRegister 并设置 cameraId
    // 注意：这里的 getRegister 函数需要能够处理从路由获取的参数
   
  }
   getRegister(deviceId).then(res => {
      data.cameraId = res.data.deviceCode;
      data.terminalId = res.data.idDeDeviceTerminalConfig;
    }).catch(error => {
      console.error("Error fetching register from route:", error);
    });

});

onMounted(() => {
  // getRegister(route.path.split("/")[3]).then(res => {
  //   data.cameraId = res.data.deviceCode;
  //   data.terminalId = res.data.idDeDeviceTerminalConfig;
  // });
});

onUnmounted(() => {
  if (socket && data.terminalId && data.cameraId) {
    const channels = [
      `edgeCameraServiceImpl/getRGBImageStream/${data.terminalId}/${data.cameraId}`,
      `edgeCameraServiceImpl/getDepthImageStream/${data.terminalId}/${data.cameraId}`,
    ];
    channels.forEach(channel => {
      socket.off(channel, data.callbacks[channel]);
      console.log('卸载时清理回调:', channel);
    });
    data.callbacks = {};
  }
  blobUrls.value.forEach(url => URL.revokeObjectURL(url));
  blobUrls.value = [];
});
</script>

<style scoped lang="scss">
.realsense-viewer {
  display: flex;
  flex-direction: column;
  flex: 1;
  background-color: #000;
  .height-full {
    height: 100%;
  }
  .control-panel {
    padding: 10px;
    .controls {
      padding: 10px;
      background-color: rgb(50, 50, 50);
      border-radius: 10px;
      .el-form {
        display: flex;
        flex-direction: column;
      }
    }
  }
  .video-panel {
    display: flex;
    flex-direction: column;
    flex-grow: 1;
    overflow: hidden;
    .single-stream-container {
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
      flex-grow: 1;
      .stream-wrapper {
        width: 100%;
        height: 100%;
        display: flex;
        justify-content: center;
        align-items: center;
        overflow: hidden;
        position: relative;
        video {
          width: auto;
          height: 100%;
          object-fit: contain;
          transition: opacity 0.1s ease-in-out; /* 平滑过渡 */
        }
      }
    }
    .stream-container {
      display: flex;
      flex-direction: column;
      flex-grow: 1;
      .stream-item {
        flex: 1;
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        .stream-wrapper {
          width: 100%;
          height: 100%;
          display: flex;
          justify-content: center;
          align-items: center;
          overflow: hidden;
          position: relative;
          video {
            width: auto;
            height: 100%;
            object-fit: contain;
            transition: opacity 0.1s ease-in-out; /* 平滑过渡 */
          }
        }
      }
    }
  }
}
</style>