<template>
  <div class="left-bottom-charts"> 
      <el-tooltip :content="!isHandSeries ? '开启触觉流': '关闭触觉流'" placement="top">
      <el-switch
          v-model="isHandSeries"
          @change="handleSwitchChange"
          style="--el-switch-on-color: #13ce66; --el-switch-off-color: #999; position: absolute;"
      />
      </el-tooltip>
      <canvas ref="handCanvas" class="hand-canvas"></canvas>
  </div>
</template>
    
<script setup >
import handImage from '@/assets/images/hand2.png';
import { inject } from 'vue';
const emit = defineEmits(['update:bottomSeriesData']);
const socket = inject('ws');
const handCanvas = ref(null);
const terminalId = ref(''); // 待您修改
const deviceId = ref(''); // 待您修改
const frameData = ref({ count: 0, lastTime: 0 });
const isHandSeries = ref(false);
const containerRef = ref(null)

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

// 2. 使用 watchEffect 来响应 props 和路由的变化
watchEffect(() => {
  terminalId.value = props.initialTerminalId;
  deviceId.value = props.initialDeviceId;
});

// 矩形定义
const rectangle = [
  { x: 24, y: 305, width: 21, height: 20, xCount: 3, yCount: 3 }, // PINKY.TIP
  { x: 17, y: 240, width: 42, height: 57, xCount: 8, yCount: 12 }, // PINKY.FINGER
  { x: 25, y: 152, width: 42, height: 51, xCount: 8, yCount: 10 }, // PINKY.PAD
  { x: 88, y: 339, width: 23, height: 22, xCount: 3, yCount: 3 }, // RING.TIP
  { x: 75, y: 276, width: 43, height: 56, xCount: 8, yCount: 12 }, // RING.FINGER
  { x: 88, y: 152, width: 44, height: 51, xCount: 8, yCount: 10 }, // RING.PAD
  { x: 153, y: 354, width: 22, height: 21, xCount: 3, yCount: 3 }, // MIDDLE_FINGER.TIP
  { x: 146, y: 283, width: 44, height: 56, xCount: 8, yCount: 12 }, // MIDDLE_FINGER.FINGER
  { x: 146, y: 152, width: 43, height: 51, xCount: 8, yCount: 10 }, // MIDDLE_FINGER.PAD
  { x: 224, y: 332, width: 23, height: 22, xCount: 3, yCount: 3 }, // INDEX.TIP
  { x: 209, y: 267, width: 44, height: 58, xCount: 8, yCount: 12 }, // INDEX.FINGER
  { x: 203, y: 152, width: 44, height: 52, xCount: 8, yCount: 10 }, // INDEX.PAD
  { x: 290, y: 225, width: 21, height: 21, xCount: 3, yCount: 3 }, // THUMB.TIP
  { x: 282, y: 161, width: 44, height: 57, xCount: 8, yCount: 12 }, // THUMB.FINGER
  { x: 289, y: 111, width: 22, height: 20, xCount: 3, yCount: 3 }, // THUMB.THUMB_MIDDLE
  { x: 269, y: 24, width: 57, height: 57, xCount: 8, yCount: 12 }, // THUMB.PAD
  { x: 53, y: 11, width: 188, height: 107, xCount: 14, yCount: 8 } // PALM.PALM_PAD
];

// 模拟的矩形数据（17 个二维数组）
const rectangleData = ref([]);

// 初始化矩形数据
const initializeRectangleData = () => {
  rectangleData.value = rectangle.map(({ xCount, yCount }) =>
    Array(yCount)
      .fill()
      .map(() => Array(xCount).fill().map(() => Math.floor(Math.random() * 0)))
  );
};


// 防抖函数
const debounce = (func, delay) => {
  let timeoutId;
  return (...args) => {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => func.apply(null, args), delay);
  };
};

// 初始化 Canvas
const initCanvas = () => {
  const canvas = handCanvas.value;
  if (!canvas) {
    console.error('Canvas element is not available');
    return;
  }

  const img = new Image();
  img.onload = () => {
    canvas.width = canvas.parentElement.offsetWidth;
    canvas.height = canvas.parentElement.offsetHeight;

    const ctx = canvas.getContext('2d');
    if (ctx) {
      drawImage(ctx, img);
      drawRectangles(ctx, img);
    } else {
      console.error('Failed to get 2D context');
    }
  };
  img.onerror = () => console.error('Failed to load image:', handImage);
  img.src = handImage;
};

// 绘制图片
const drawImage = (ctx, img) => {
  const { width: canvasWidth, height: canvasHeight } = ctx.canvas;
  const aspectRatio = img.width / img.height;

  let drawWidth, drawHeight;
  if (canvasWidth / canvasHeight > aspectRatio) {
    drawHeight = canvasHeight;
    drawWidth = drawHeight * aspectRatio;
  } else {
    drawWidth = canvasWidth;
    drawHeight = drawWidth / aspectRatio;
  }

  const x = (canvasWidth - drawWidth) / 2;
  const y = canvasHeight - drawHeight;

  ctx.drawImage(img, x, y, drawWidth, drawHeight);
};

// 绘制矩形
const drawRectangles = (ctx, img) => {
  const { width: canvasWidth, height: canvasHeight } = ctx.canvas;
  const aspectRatio = img.width / img.height;

  let drawWidth, drawHeight;
  if (canvasWidth / canvasHeight > aspectRatio) {
    drawHeight = canvasHeight;
    drawWidth = drawHeight * aspectRatio;
  } else {
    drawWidth = canvasWidth;
    drawHeight = drawWidth / aspectRatio;
  }

  const xOffset = Math.round((canvasWidth - drawWidth) / 2);
  const yOffset = Math.round(canvasHeight - drawHeight);

  const scaleX = drawWidth / img.width;
  const scaleY = drawHeight / img.height;

  rectangle.forEach((rect, index) => {
    const x = Math.round(xOffset + rect.x * scaleX);
    const y = Math.round(yOffset + (img.height - rect.y - rect.height) * scaleY);
    const rectWidth = Math.round(rect.width * scaleX);
    const rectHeight = Math.round(rect.height * scaleY);
    const smallWidth = Math.round(rectWidth / rect.xCount);
    const smallHeight = Math.round(rectHeight / rect.yCount);

    const data = rectangleData.value[index];
    if (!data) {
      console.warn(`No data for rectangle at index ${index}`);
      return;
    }

    for (let i = 0; i < rect.xCount; i++) {
      for (let j = 0; j < rect.yCount; j++) {
        const smallX = x + i * smallWidth;
        const smallY = y + j * smallHeight;
        const value = data[j][i];
        // 非常淡橙色 (#FFF5E1, RGB: 255, 245, 225) 到深红 (#800000, RGB: 128, 0, 0)
        const r = 128 + Math.floor(((255 - 128) * (4096 - value) + (128 - 0) * value) / 4096);
        const g = Math.floor((245 * (4096 - value) + 0 * value) / 4096);
        const b = Math.floor((225 * (4096 - value) + 0 * value) / 4096);
        ctx.fillStyle = `rgb(${r}, ${g}, ${b})`;
        ctx.fillRect(smallX, smallY, smallWidth, smallHeight);
      }
    }
  });
};

// 更新 Canvas
const updateCanvas = () => {
  const canvas = handCanvas.value;
  if (!canvas) {
    console.error('Canvas element is not available during update');
    return;
  }

  const img = new Image();
  img.onload = () => {
    canvas.width = canvas.parentElement.offsetWidth;
    canvas.height = canvas.parentElement.offsetHeight;

    const ctx = canvas.getContext('2d');
    if (ctx) {
      drawImage(ctx, img);
      drawRectangles(ctx, img);
    }
  };
  img.onerror = () => console.error('Failed to load image:', handImage);
  img.src = handImage;
};

// 传感器到图表的映射
const sensorMap = [
  { fingerType: 'PINKY', partType: 'TIP', key: 'littleFinger.end' },
  { fingerType: 'PINKY', partType: 'FINGER', key: 'littleFinger.tip' },
  { fingerType: 'PINKY', partType: 'PAD', key: 'littleFinger.middle' },
  { fingerType: 'RING', partType: 'TIP', key: 'ringFinger.end' },
  { fingerType: 'RING', partType: 'FINGER', key: 'ringFinger.tip' },
  { fingerType: 'RING', partType: 'PAD', key: 'ringFinger.middle' },
  { fingerType: 'MIDDLE_FINGER', partType: 'TIP', key: 'middleFinger.end' },
  { fingerType: 'MIDDLE_FINGER', partType: 'FINGER', key: 'middleFinger.tip' },
  { fingerType: 'MIDDLE_FINGER', partType: 'PAD', key: 'middleFinger.middle' },
  { fingerType: 'INDEX', partType: 'TIP', key: 'indexFinger.end' },
  { fingerType: 'INDEX', partType: 'FINGER', key: 'indexFinger.tip' },
  { fingerType: 'INDEX', partType: 'PAD', key: 'indexFinger.middle' },
  { fingerType: 'THUMB', partType: 'TIP', key: 'thumb.end' },
  { fingerType: 'THUMB', partType: 'FINGER', key: 'thumb.tip' },
  { fingerType: 'THUMB', partType: 'THUMB_MIDDLE', key: 'thumb.middle' },
  { fingerType: 'THUMB', partType: 'PAD', key: 'thumb.palm' },
  { fingerType: 'PALM', partType: 'PALM_PAD', key: 'palm.touch' }
];

// WebSocket 订阅
const subscribeSensorData = async (sub) => {
  if (!socket || !terminalId.value || !deviceId.value) {
    console.warn(`订阅失败: socket=${!!socket}, terminalId=${terminalId.value}, deviceId=${deviceId.value}`);
    return;
  }
  const channel = `edgeDexHandServiceImpl/getSensorDataStream/${terminalId.value}/${deviceId.value}`;
  console.log(sub ? '订阅' : '取消订阅', channel);
  socket.send({
    type: 'channel_subscription',
    action: sub ? 'subscribe' : 'unsubscribe',
    channel
  });

  if (sub) {
    await nextTick();
    if (data.callback) {
      socket.off(channel, data.callback);
      console.log('清理旧回调:', channel);
    }

    const callback = (playLoad) => {
      requestAnimationFrame(() => {
        const start = performance.now();
        try {
          // 解析 playLoad
          const sensorData = typeof playLoad === 'string' ? JSON.parse(playLoad) : playLoad;
          if (!Array.isArray(sensorData) || sensorData.length !== 17) {
            console.error('无效的 payload 格式: 期望 17 个传感器对象', sensorData);
            return;
          }

          // 转换为 rectangleData 和计算 maxData, avgData
          const newRectangleData = sensorData.map((sensor, index) => {
            const { xCount, yCount } = rectangle[index];
            const { rows, cols, dataList } = sensor;

            // 验证尺寸
            if (rows !== yCount || cols !== xCount || !Array.isArray(dataList) || dataList.length !== rows) {
              console.error(`传感器 ${sensor.sensorName} 数据尺寸不匹配: 期望 ${yCount}x${xCount}, 实际 ${rows}x${cols}`);
              return rectangleData.value[index] || Array(yCount).fill().map(() => Array(xCount).fill(0));
            }

            // 提取 valuesList
            return dataList.map(row => {
              if (!row || !Array.isArray(row.valuesList) || row.valuesList.length !== cols) {
                console.warn(`传感器 ${sensor.sensorName} 行数据无效`);
                return Array(xCount).fill(0);
              }
              return row.valuesList;
            });
          });

          // 计算 maxData 和 avgData
          const newMaxData = {
            thumb: { end: 0, tip: 0, middle: 0, palm: 0 },
            indexFinger: { end: 0, tip: 0, middle: 0 },
            middleFinger: { end: 0, tip: 0, middle: 0 },
            ringFinger: { end: 0, tip: 0, middle: 0 },
            littleFinger: { end: 0, tip: 0, middle: 0 },
            palm: { touch: 0 }
          };
          const newAvgData = {
            thumb: { end: 0, tip: 0, middle: 0, palm: 0 },
            indexFinger: { end: 0, tip: 0, middle: 0 },
            middleFinger: { end: 0, tip: 0, middle: 0 },
            ringFinger: { end: 0, tip: 0, middle: 0 },
            littleFinger: { end: 0, tip: 0, middle: 0 },
            palm: { touch: 0 }
          };

          sensorData.forEach((sensor, index) => {
            const { dataList, fingerType, partType } = sensor;
            const map = sensorMap[index];
            if (!map || map.fingerType !== fingerType || map.partType !== partType) {
              console.warn(`传感器 ${sensor.sensorName} 映射不匹配: 期望 ${map.fingerType}.${map.partType}`);
              return;
            }

            // 计算最大值和平均值
            let maxValue = 0;
            let sum = 0;
            let count = 0;
            dataList.forEach(row => {
              row.valuesList.forEach(value => {
                maxValue = Math.max(maxValue, value);
                if (value > 0) {
                  sum += value;
                  count++;
                }
              });
            });
            const avgValue = count > 0 ? sum / count : 0;

            // 更新 maxData 和 avgData
            const [finger, part] = map.key.split('.');
            newMaxData[finger][part] = Math.floor(maxValue);
            newAvgData[finger][part] = Math.floor(avgValue);
          });

          // 更新 rectangleData 和 maxData, avgData
          rectangleData.value = newRectangleData;
          emit('update:topSeriesData', {maxData: newMaxData, avgData: newAvgData});

          // 更新 Canvas
          updateCanvas();

          // 帧率和性能监控
          frameData.value.count++;
          const currentTime = performance.now();
          if (frameData.value.lastTime && currentTime - frameData.value.lastTime >= 1000) {
            const fps = frameData.value.count * 1000 / (currentTime - frameData.value.lastTime);
            console.log(`渲染帧率: ${fps.toFixed(2)} fps, 通道: ${channel}`);
            frameData.value.count = 0;
            frameData.value.lastTime = currentTime;
          } else if (!frameData.value.lastTime) {
            frameData.value.lastTime = currentTime;
          }
          console.log(`数据更新耗时: ${(performance.now() - start).toFixed(2)}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'
            });
          }
        } catch (err) {
          console.error('数据更新失败:', err, '通道:', channel);
          console.error('payload 数据:', playLoad);
        }
      });
    };
    socket.on(channel, callback);
    data.callback = callback;
    console.log('注册新回调:', channel);
  } else {
    if (data.callback) {
      socket.off(channel, data.callback);
      delete data.callback;
      console.log('清理回调:', channel);
    }
  }
};

// 数据对象
const data = reactive({
  callback: null
});


const handleSwitchChange = (val) => {
  subscribeSensorData(val)
}

// 生命周期钩子
onMounted(async () => {
  await nextTick();
  initializeRectangleData(); // 初始化数据
  initCanvas(); // 初始化 Canvas

// 使用 ResizeObserver 监听父容器尺寸变化
  const container = containerRef.value || handCanvas.value?.parentElement;
  if (container) {
    const resizeObserver = new ResizeObserver(debounce(updateCanvas, 10));
    resizeObserver.observe(container);
    // 保存 ResizeObserver 实例以便清理
    data.resizeObserver = resizeObserver;
  } else {
    console.error('Failed to find container for ResizeObserver');
  }

  const debouncedResize = debounce(updateCanvas, 10);
  window.addEventListener('resize', debouncedResize);
  data.debouncedResize = debouncedResize; // 保存以便清理



});

onUnmounted(() => {
  // 清理 ResizeObserver
  if (data.resizeObserver) {
    data.resizeObserver.disconnect();
    delete data.resizeObserver;
  }
  // 清理 window 的 resize 事件
  if (data.debouncedResize) {
    window.removeEventListener('resize', data.debouncedResize);
    delete data.debouncedResize;
  }
  // 清理 WebSocket 订阅
  if (isHandSeries.value) {
    subscribeSensorData(false);
  }
});
</script>
    
<style>
.left-bottom-charts {
  height: 100%;
}    
.hand-canvas {
  width: 100%;
  height: 100%;
  object-fit: contain;
}
</style>