<template>
  <div>
    <canvas ref="canvasRef" :width="clientObj.width" :height="clientObj.height"></canvas>
  </div>
</template>

<script setup name="HumanBody" lang="ts">
import { initSpeech, speckText, playMusic, controlMusic, speckCancel, chineseNumber } from '@/utils/speech';
import { useWebSocket } from '@/utils/bodyposeWs';
const { proxy } = getCurrentInstance() as any;
const router = useRouter();
const { bodyposeWs, startDevice, checkBodypose, openBodypose, terminateBodypose, suspendBodypose, resumeBodypose, getBodyposeState, closeWS } = useWebSocket();
const canvasRef = ref(null);

const data = reactive<any>({
  bodyposeData: {},//姿态信息
  bodyposeState: false,//姿态识别窗口状态
  parameter: {},//参数
  deviceInfo: {},//设备信息
  againNum: 0,//再次启动次数
  againTimer: null,//定时状态
  wsState: false,//WS状态
  clientObj: {},//浏览器对象
  boxes: [],//四个点坐标
  proportion: null,//人框和屏幕比例
});

const { bodyposeData, bodyposeState, parameter, deviceInfo, againNum, againTimer, wsState, clientObj, boxes, proportion } = toRefs(data);

/**
 * 初始化
 */
const getInit = async () => {
  console.log("触发姿态识别")
  let deviceid = localStorage.getItem('deviceid') || '';
  if (!deviceid) {
    proxy?.$modal.msgError(`请重新登录绑定设备号后使用`);
    return false;
  }
  bodyposeState.value = true;
  if (wsState.value) {
    proxy?.$modal.msgWarning(`操作过快，请稍后重试`);
    setTimeout(() => {
      bodyposeState.value = false;
    }, 1000)
    return false;
  }
  speckText("正在姿态识别");
  proxy?.$modal.msgWarning(`正在姿态识别`);
  bodyposeWs((e: any) => {
    console.log("bodyposeWS", e)
    if (e?.wksid) {
      wsState.value = true;
      //获取设备信息
      startDevice({ deviceid: deviceid });
      console.log("获取设备信息")
    }
    if (e?.type == 'fe_device_init_result') {
      //接收设备信息并发送请求
      if (e?.device_info) {
        deviceInfo.value = e.device_info;
        getCheckBodypose();
        console.log("返回设备信息，检查是否支持姿态识别")
      } else {
        proxy?.$modal.msgError(`设备信息缺失，请重新登录绑定设备号后使用`);
      }
    }
    if (e?.cmd == 'check_bodyposecontroller_available') {
      let handcontroller_id = deviceInfo.value.handcontroller_id;
      if (e?.code == 0) {
        //查看姿态识别状态，如果不处于关闭就先关闭再重新启动（可能会APP退出然后工作站还在运行的可能性）
        getBodyposeState(handcontroller_id);
        againNum.value = 0;
        againTimer.value = null;
        clearTimeout(againTimer.value);
        console.log("查看姿态识别状态")
      } else {
        //尝试多次查询姿态识别状态
        if (againNum.value <= 2) {
          againTimer.value = setTimeout(() => {
            getCheckBodypose();
          }, 500)
          againNum.value++;
        } else {
          let msg = "";
          if (e.code == 102402) {
            msg = `多次连接失败请重试，姿态识别模块被占用`;
          } else {
            msg = `多次连接失败请重试，姿态识别模块不可用，code：${e.code}`;
          }
          proxy?.$modal.msgWarning(msg);
          againNum.value = 0;
          againTimer.value = null;
          clearTimeout(againTimer.value);
          getCloseBodypose();//直接关闭 
        }

      }
    }
    if (e?.cmd == 'get_bodyposecontroller_state') {
      let handcontroller_id = deviceInfo.value.handcontroller_id;
      //state说明: 0：关闭，3：空闲，36：工作中
      if ([3, 36].includes(e.state)) {
        getCloseBodypose();
        proxy?.$modal.msgWarning(`请重新姿态识别`);
      } else {
        openBodypose(handcontroller_id);
      }
    }
    if (e?.type == 'bodyposecontroller_result') {
      let arr = e.data.result.keypoints;
      let result = [];
      for (let i = 0; i < arr.length; i += 3) {
        result.push(arr.slice(i, i + 2));
      }
      console.log("result", result)
      bodyposeData.value = result;
      if (boxes.value.length == 0) {
        speckText("识别成功");
        proxy?.$modal.msgWarning(`识别成功`);
        let arr = e.data.result.boxes;
        boxes.value = [{ x: arr[0], y: arr[3] }, { x: arr[0], y: arr[1] }, { x: arr[2], y: arr[1] }, { x: arr[2], y: arr[3] }]
        proportion.value = (clientObj.value.height / (arr[3] - arr[1])).toFixed(2);
      }
      //绘制图案
      getCanvas();
    }
    if (e?.cmd == 'terminate_bodyposecontroller') {
      if (e?.code == 0) {
        closeWS();
        bodyposeState.value = false;
      }
    }
    if (e?.type == 'disconnect') {
      wsState.value = false;
    }
  });
};


/**
 * 查询姿态识别状态
*/
const getCheckBodypose = () => {
  let handcontroller_id = deviceInfo.value.handcontroller_id;
  //检查是否支持姿态识别
  checkBodypose(handcontroller_id);
};

/**
 * 关闭姿态识别
*/
const getCloseBodypose = () => {
  let handcontroller_id = deviceInfo.value.handcontroller_id;
  terminateBodypose(handcontroller_id);
  bodyposeState.value = false;
  speckCancel(); //停止播报
  setTimeout(() => {
    if (wsState.value) {
      closeWS();
    }
  }, 3000)
};

/**
 * 绘图
*/
const getCanvas = () => {
  const canvas: any = canvasRef.value;
  const ctx = canvas.getContext('2d');
  // 清空整个画布
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  // 保存当前状态 
  ctx.save();
  function calculateOffset(a: any, b: any) {
    return {
      x: b.x - a.x,
      y: b.y - a.y
    };
  }
  const pointA = { x: clientObj.value.width / 2, y: clientObj.value.height / 2 };
  const pointB = { x: (boxes.value[2].x + boxes.value[0].x) / 2, y: (boxes.value[3].y + boxes.value[1].y) / 2 };
  const offset = calculateOffset(pointA, pointB);
  ctx.translate(-offset.x, -offset.y);
  // console.log("Canvas分辨率", clientObj.value);
  // console.log("人体图片四点坐标", boxes.value)
  // console.log("Canvas中心", pointA);
  // console.log("人体中心", pointB);
  // console.log("offset", offset)
  // console.log("proportion.value",proportion.value)
  const originalPoints = bodyposeData.value;
  // 计算缩放后坐标
  const postData = originalPoints.map((point: any) => {
    const newX = (point[0] - pointB.x) * proportion.value + pointB.x;
    const newY = (point[1] - pointB.y) * proportion.value + pointB.y;
    return [newX, newY];
  });
  // console.log("原始坐标：", originalPoints);
  // console.log("缩放后坐标：", postData);

  //绘制头部
  const point1 = { x: postData[4][0], y: postData[4][1] };
  const point2 = { x: postData[3][0], y: postData[3][1] };
  // 计算椭圆参数
  const centerX = (point1.x + point2.x) / 2; // 椭圆中心X
  const centerY = (point1.y + point2.y) / 2; // 椭圆中心Y
  const distance = Math.sqrt(
    Math.pow(point2.x - point1.x, 2) +
    Math.pow(point2.y - point1.y, 2)
  ); // 两个焦点之间的距离
  const radiusX = distance * 0.5; // 水平半径（可调整）
  const radiusY = distance * 0.6; // 垂直半径（可调整）
  // 1. 绘制填充椭圆
  ctx.beginPath();
  ctx.ellipse(centerX, centerY, radiusX, radiusY, 0, 0, Math.PI * 2);
  ctx.fillStyle = 'red'; // 填充颜色
  ctx.fill(); // 填充
  // 2. 绘制边框
  ctx.strokeStyle = 'red';
  ctx.lineWidth = 5;
  ctx.stroke();
  // 绘制每个点
  postData.forEach((point: any, index) => {
    //眼睛鼻子不显示
    if ([0, 1, 2].includes(index)) {
      const [x, y] = point;
      ctx.beginPath();
      ctx.arc(x, y, 5, 0, Math.PI * 2); // 绘制半径为5的圆点
      ctx.fillStyle = 'red';
      ctx.fill();
      ctx.lineWidth = 1;
      ctx.stroke();
    }
  });
  // 根据点关系连线
  const arr = [[10, 8], [8, 6], [6, 5], [5, 7], [7, 9], [6, 12], [5, 11], [12, 11], [12, 14], [14, 16], [11, 13], [13, 15]]
  arr.forEach((point: any) => {
    let index1 = point[0];
    let index2 = point[1];
    //连线
    const dian1 = { x: postData[index1][0], y: postData[index1][1] };
    const dian2 = { x: postData[index2][0], y: postData[index2][1] };
    // 绘制连线
    ctx.beginPath();
    ctx.moveTo(dian1.x, dian1.y); // 起点
    ctx.lineTo(dian2.x, dian2.y); // 终点
    ctx.strokeStyle = 'red'; // 线条颜色
    ctx.lineWidth = 3; // 线条宽度
    ctx.stroke(); // 描边
  });
  ctx.restore(); // 恢复状态
};

onBeforeMount(() => {
  clientObj.value = {
    width: document.documentElement.clientWidth,
    height: document.documentElement.clientHeight,
  }
  getInit();
});

onMounted(() => {
})

onBeforeUnmount(() => {
  closeWS();
});
</script>

<style lang="scss" scoped></style>
