<template>

  <div class="main_container" ref="mainContainer" v-loading="loading" element-loading-text="图片加载中……" element-loading-spinner="el-icon-loading" element-loading-background="#ffffff"  @wheel="onWheel">
   
      <canvas  ref="paperCanvas" class="paper_canvas"   :width="canvasInfo.width" :height="canvasInfo.height" @mousedown="startDrag" @mousemove="onDrag" @mouseup="stopDrag"></canvas>
        
  </div>
  
</template>
<script setup>
import { ref, reactive, watch, onMounted, onBeforeUnmount, nextTick } from 'vue';
import { throttle } from 'lodash';
import positionIcon from '../assets/icon/position_icon.png';
// props定义
const props = defineProps({
  paperType: {
    type: String,
    default: 'student'
  },//类型 模板 还是学生

  usedCardType: {
    type: [Number, String],
    default: 1
  },//系统卡 还是三方卡   0-未制卡 1-系统卡 2-三方卡

  paperImgUrl: {
    type: String,
    default: ''
  },//试卷地址

  positionList: {
    type: Array,
    default: () => []
  }//定位点坐标列表 {x:0,y:0}
});

// emit定义
const emit = defineEmits(['GetCutPosition']);

// 鼠标拖动相关
const startX = ref(0);//鼠标按下时的初始位置x坐标
const startY = ref(0);//鼠标按下时的初始位置y坐标
const currentX = ref(0);//试卷的位置  相对于canvas
const currentY = ref(0);//试卷的位置  相对于canvas
const scale = ref(1);//画布缩放倍数
const isDragging = ref(false);
const loading = ref(false);//加载loading

// 图片对象
const image = new Image();

// 试卷显示的大小
const paperImgInfo = reactive({
  width: 0,
  height: 0
});

// 画布的大小
const canvasInfo = reactive({
  width: 1240,
  height: 1754
});

// 显示的图片的大小
const imageSize = reactive({
  width: 0,
  height: 0
});

// canvas相关
const paperCanvas = ref(null);//试卷画布
const paperCtx = ref(null);
const zoomRate = ref(1);//图片的缩放比例

// 定位点坐标
const point1 = reactive({
  x: 30,
  y: 25
});//定位一坐标点

const point2 = reactive({
  x: 0,
  y: 0
});//定位2的坐标点

const point3 = reactive({
  x: 33,
  y: 44
});//定位3的坐标

const point4 = reactive({
  x: 0,
  y: 0
});//定位4的坐标

// 定位点拖动状态
const isDragging1 = ref(false);//是否可以拖动定位1
const isDragging2 = ref(false);//是否可以拖动定位2
const isDragging3 = ref(false);//是否可以拖动定位3
const isDragging4 = ref(false);//是否可以拖动定位4

// 旋转相关
const rotationAngle = ref(0);//初始旋转角度
const rotate = ref(0);//选择记录  0 未旋转  1 顺时针90  2 顺时针180  3 顺时针270
const iconWidth = ref(40);//图标宽度
const iconHeight = ref(40);//图标高度

// 重绘控制
const redrawPending = ref(false);//用与防止多次请求重绘画布
const animationId = ref(null);

// 容器引用
const mainContainer = ref(null);

// 监听试卷地址变化
watch(() => props.paperImgUrl, () => {
  console.log("地址变化了", props.paperImgUrl);
  console.log("打印positionList", props.positionList);
  InitCanvasData();//初始化数据
});

// 监听定位点坐标变化
watch(() => props.positionList, (newVal) => {
  console.log("坐标变化了", props.positionList);
  // 只在有图片且画布已初始化时才更新标注位置
  if (image.src && paperCtx.value && newVal && newVal.length > 0) {
    if (props.usedCardType == 1) {
      // 系统卡：更新4个定位点
      if (newVal.length >= 4) {
        Object.assign(point1, newVal[0]);
        Object.assign(point2, newVal[1]);
        Object.assign(point3, newVal[2]);
        Object.assign(point4, newVal[3]);
      }
    } else {
      // 三方卡：更新2个定位点
      if (newVal.length >= 2) {
        Object.assign(point1, newVal[0]);
        Object.assign(point3, newVal[2]);
      }
    }
    
    // 只重绘定位点，不重新加载图片
    RequestRedraw();
  }
});

// 组件挂载
onMounted(() => {
  InitCanvasData();//初始化数据
});

// 组件卸载前
onBeforeUnmount(() => {
  // 取消未完成的动画请求
  if (animationId.value) {
    cancelAnimationFrame(animationId.value);
  }
});

// 适应屏幕
const FitScreen = () => {
  InitCanvasData();//初始化数据
};

// 加载图片
const LoadImage = () => {
  image.src = props.paperImgUrl;
  image.crossOrigin = "Anonymous";//设置跨域属性  不设置跨域 导出的图片没有图片
  image.onload = () => {
    DrawImage();
    DrawPosition();//加载定位点坐标
  };
};

// 初始画布数据加载
const InitCanvasData = () => {
  let { width, height } = mainContainer.value.getBoundingClientRect();
  loading.value = true;
  console.log("打印容器宽高", width, height);
  rotationAngle.value = 0;
  canvasInfo.width = width;
  canvasInfo.height = height;
  paperCanvas.value = mainContainer.value.querySelector('.paper_canvas');
  paperCtx.value = paperCanvas.value.getContext('2d');
  console.log("打印this.paperCtx", paperCtx.value);
  image.src = props.paperImgUrl;

  image.crossOrigin = "Anonymous";//设置跨域属性  不设置跨域 导出的图片没有图片
  image.onload = () => {
    // 使用 nextTick 确保 DOM 更新后再执行计算
    nextTick(() => {
      console.log("图片加载成功", image.width, image.height);
      
      // 优化缩放比例计算逻辑
      const containerPadding = 20; // 容器内边距
      let widthScale = (canvasInfo.width - containerPadding) / image.width;
      let heightScale = (canvasInfo.height - containerPadding) / image.height;
      
      // 选择较小的缩放比例以确保图片完整显示
      zoomRate.value = Math.min(widthScale, heightScale);
      scale.value = 1;//初始默认1
      console.log("打印初始缩放比例是", zoomRate.value);
      
      // 计算图片显示的宽高
      paperImgInfo.width = image.width * zoomRate.value;
      paperImgInfo.height = image.height * zoomRate.value;
      console.log("打印图片的地址", props.paperImgUrl);
      
      // 计算图片的位置
      currentX.value = (canvasInfo.width - paperImgInfo.width * scale.value) / 2;
      currentY.value = (canvasInfo.height - paperImgInfo.height * scale.value) / 2;
      
      // 坐标位置 左上 右上 右下 左下   黑块的坐标  30 25  黑块的宽高 25 15
      if (props.usedCardType == 1) {
        console.log("系统卡,定位点", props.positionList);
        if (props.positionList.length > 0) {
          // 系统卡
          Object.assign(point1, props.positionList[0]);//左上
          Object.assign(point2, props.positionList[1]);//右上
          Object.assign(point3, props.positionList[2]);//右下
          Object.assign(point4, props.positionList[3]);//左下
        } else {
          // 系统卡默认坐标
          Object.assign(point1, { x: 30, y: 25 });//左上
          Object.assign(point2, { x: image.width - 30, y: 25 });//右上
          Object.assign(point3, { x: image.width - 30, y: image.height - 25 });//右下
          Object.assign(point4, { x: 30, y: image.height - 25 });//左下
        }
      } else {
        console.log("三方卡,定位点为空,使用默认坐标");
        // 三方卡
        if (props.positionList.length > 0) {
          Object.assign(point1, props.positionList[0]);//左上
          Object.assign(point2, props.positionList[1]);//右上
          Object.assign(point3, props.positionList[2]);//右下
          Object.assign(point4, props.positionList[3]);//左下
        } else {
          // 三方卡默认坐标
          Object.assign(point1, { x: 30, y: 25 });//左上
          Object.assign(point2, { x: image.width - 30, y: 25 });//右上
          Object.assign(point3, { x: image.width - 30, y: image.height - 25 });//右下
          Object.assign(point4, { x: 30, y: image.height - 25 });//左下
        }
      }
      
      setTimeout(() => { 
        loading.value = false;
      }, 500);
      
      // 使用 Promise 确保所有计算完成后再加载图片
      Promise.resolve().then(() => {
        LoadImage();
      }).catch(error => {
        console.error('加载图片时出错:', error);
      });
    });
  };

  setTimeout(() => { 
    loading.value = false;
  }, 2500);
};

// 根据地址获取旋转角度
const GetRotationFromUrl = (url) => {
  if (!url) return 0;
  
  // 匹配 x-oss-process=image/rotate,xxx 格式的旋转参数
  const rotateRegex = /x-oss-process=image\/rotate,(\d+)/;
  const match = url.match(rotateRegex);
  
  if (match && match[1]) {
    return parseInt(match[1], 10);
  }
  
  return 0;
};

// 判断鼠标位置是否在定位点的图标内
const CheckPointInIcon = (x, y, point) => {
  const iconW = iconWidth.value * scale.value;
  const iconH = iconHeight.value * scale.value;
  const rect = {
    left: point.x * zoomRate.value * scale.value + currentX.value - iconW / 2,
    right: point.x * zoomRate.value * scale.value + currentX.value + iconW / 2,
    top: point.y * zoomRate.value * scale.value + currentY.value - iconH / 2,
    bottom: point.y * zoomRate.value * scale.value + currentY.value + iconH / 2,
  };
  
  let result = false;
  if (x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom) {
    result = true;
  }
  return result;
};

// 选择图片  顺时针旋转
const ClockwiseRotateImage = () => {
  // 每次点击时增加旋转角度
  rotationAngle.value += 90;
  RequestRedraw();//请求重绘
};

// 逆时针旋转图片
const AnticlockwiseRotateImage = () => {
  // 每次点击时增加旋转角度
  rotationAngle.value -= 90;
  rotate.value -= 1;
  RequestRedraw();//请求重绘
};

// 放大图片
const ZoomIn = (event) => {
  // 如果有鼠标事件，则以鼠标位置为中心进行缩放
  let mouseX, mouseY;
  if (event) {
    const rect = mainContainer.value.getBoundingClientRect();
    mouseX = event.clientX - rect.left;
    mouseY = event.clientY - rect.top;
  } else {
    // 如果没有鼠标事件，默认以图片中心点缩放
    mouseX = canvasInfo.width / 2;
    mouseY = canvasInfo.height / 2;
  }

  // 计算鼠标在图片上的相对位置 (0-1之间)
  const relativeX = (mouseX - currentX.value) / (paperImgInfo.width * scale.value);
  const relativeY = (mouseY - currentY.value) / (paperImgInfo.height * scale.value);

  // 向上滚动放大
  const oldScale = scale.value;
  scale.value *= 1.1;
  // 确保缩放比例不小于最小值
  if (scale.value > 2.5) {
    scale.value = 2.5;
  }

  // 如果确实发生了缩放
  if (scale.value !== oldScale) {
    // 根据相对位置调整图片位置，使鼠标位置保持不变
    currentX.value = mouseX - (relativeX * paperImgInfo.width * scale.value);
    currentY.value = mouseY - (relativeY * paperImgInfo.height * scale.value);
  }
  RequestRedraw();//请求重绘
};

// 缩小图片
const ZoomOut = (event) => {
  // 如果有鼠标事件，则以鼠标位置为中心进行缩放
  let mouseX, mouseY;
  if (event) {
    const rect = mainContainer.value.getBoundingClientRect();
    mouseX = event.clientX - rect.left;
    mouseY = event.clientY - rect.top;
  } else {
    // 如果没有鼠标事件，默认以图片中心点缩放
    mouseX = canvasInfo.width / 2;
    mouseY = canvasInfo.height / 2;
  }

  // 计算鼠标在图片上的相对位置 (0-1之间)
  const relativeX = (mouseX - currentX.value) / (paperImgInfo.width * scale.value);
  const relativeY = (mouseY - currentY.value) / (paperImgInfo.height * scale.value);
  
  // 向下滚动缩小
  const oldScale = scale.value;
  scale.value /= 1.1;
  
  // 确保缩放比例不小于最小值
  if (scale.value < 0.5) {
    scale.value = 0.5;
  }

  // 如果确实发生了缩放
  if (scale.value !== oldScale) {
    // 根据相对位置调整图片位置，使鼠标位置保持不变
    currentX.value = mouseX - (relativeX * paperImgInfo.width * scale.value);
    currentY.value = mouseY - (relativeY * paperImgInfo.height * scale.value);
  }
  RequestRedraw();//请求重绘
};

// 绘制图片
const DrawImage = () => {
  // 图片加载完成后在canvas上绘制图片
  if (image) {
    // 清除之前绘制的内容
    paperCtx.value.clearRect(0, 0, canvasInfo.width, canvasInfo.height);
    paperCtx.value.drawImage(image, currentX.value, currentY.value, paperImgInfo.width * scale.value, paperImgInfo.height * scale.value);
  }
};

// 加载定位图标
const DrawPosition = () => {
  let positionImg = new Image();
  positionImg.src = positionIcon;
  positionImg.onload = () => {
    // 重新计算坐标的位置点
    const iconW = iconWidth.value * scale.value; 
    const iconH = iconHeight.value * scale.value;
    let pointlist = [point1, point2, point3, point4];
    
    if (props.positionList.length > 0) {
      pointlist = props.positionList;
      if (props.usedCardType == 1) {
        // 系统卡
        pointlist = props.positionList;
      } else {
        // 三方卡
        pointlist = [point1, point3];
      }
    } else {
      if (props.usedCardType == 1) {
        // 系统卡
        pointlist = [point1, point2, point3, point4];
      } else {
        // 三方卡
        pointlist = [point1, point3];
      }
    }

    pointlist.forEach((point) => {
      // 修改为使用相对于原始图片的px单位坐标
      const x = currentX.value + point.x * zoomRate.value * scale.value - iconW / 2;
      const y = currentY.value + point.y * zoomRate.value * scale.value - iconH / 2;
      paperCtx.value.drawImage(positionImg, x, y, iconW, iconH);
    });
  };
};

// 请求重绘
const RequestRedraw = (point) => {
  if (!redrawPending.value) {
    redrawPending.value = true;
    animationId.value = requestAnimationFrame(() => {
      if (point) {
        LoadImage();//重新加载
      } else {
        DrawImage();
        DrawPosition();
      }
      redrawPending.value = false;
    });
  }
};

// 开始拖动时记录起始位置和偏移量
const startDrag = (event) => {
  startX.value = event.clientX - currentX.value;
  startY.value = event.clientY - currentY.value;
  const rect = paperCanvas.value.getBoundingClientRect();
  const mouseX = event.clientX - rect.left;
  const mouseY = event.clientY - rect.top;
  
  if (CheckPointInIcon(mouseX, mouseY, point1)) {
    if (props.paperType == 'template') {
      return;//模板阻止拖动
    }
    event.stopPropagation();//阻止事件冒泡
    // 判断是否可以拖动
    isDragging1.value = true;
    isDragging2.value = false;
    isDragging3.value = false;
    isDragging4.value = false;
    isDragging.value = false;
    paperCanvas.value.style.cursor = "pointer";
  } else if (CheckPointInIcon(mouseX, mouseY, point2)) {
    if (props.paperType == 'template') {
      return;//模板阻止拖动
    }
    event.stopPropagation();//阻止事件冒泡
    isDragging1.value = false;
    isDragging2.value = true;
    isDragging3.value = false;
    isDragging4.value = false;
    isDragging.value = false;
  } else if (CheckPointInIcon(mouseX, mouseY, point3)) {
    if (props.paperType == 'template') {
      return;//模板阻止拖动
    }
    event.stopPropagation();//阻止事件冒泡
    isDragging1.value = false;
    isDragging2.value = false;
    isDragging3.value = true;
    isDragging4.value = false;
    isDragging.value = false;
  } else if (CheckPointInIcon(mouseX, mouseY, point4)) {
    if (props.paperType == 'template') {
      return;//模板阻止拖动
    }
    event.stopPropagation();//阻止事件冒泡
    isDragging1.value = false;
    isDragging2.value = false;
    isDragging3.value = false;
    isDragging4.value = true;
    isDragging.value = false;
  } else {
    isDragging1.value = false;
    isDragging2.value = false;
    isDragging3.value = false;
    isDragging4.value = false;
    isDragging.value = true;
  }
};

// 方法结束时重置拖动状态
const stopDrag = () => {
  isDragging.value = false;
  isDragging1.value = false;
  isDragging2.value = false;
  isDragging3.value = false;
  isDragging4.value = false;
};

// 拖动过程更新图片位置并重新绘制
const onDrag = (event) => {
  if (isDragging.value) {
    const newX = event.clientX - startX.value;
    const newY = event.clientY - startY.value;
    currentX.value = newX;
    currentY.value = newY;
    RequestRedraw();//请求重绘
  }
  
  const rect = paperCanvas.value.getBoundingClientRect();
  const mouseX = event.clientX - rect.left;
  const mouseY = event.clientY - rect.top;

  // 这里需要返回原图的px坐标 定位块中心点的坐标
  const iconW = iconWidth.value * scale.value;
  const iconH = iconHeight.value * scale.value;
  
  const newPoint = {
    x: Math.round((mouseX - currentX.value) / (zoomRate.value * scale.value)),
    y: Math.round((mouseY - currentY.value) / (zoomRate.value * scale.value))
  };
  
  // 坐标点一
  if (isDragging1.value) {
    Object.assign(point1, newPoint);
    RequestRedraw(point1);//请求重绘
    let list = [point1, point2, point3, point4];
    emit("GetCutPosition", list);
  }
  if (isDragging2.value) {
    Object.assign(point2, newPoint);
    RequestRedraw(point2);//请求重绘
    let list = [point1, point2, point3, point4];
    emit("GetCutPosition", list);
  }
  if (isDragging3.value) {
    Object.assign(point3, newPoint);
    RequestRedraw(point3);//请求重绘
    let list = [point1, point2, point3, point4];
    emit("GetCutPosition", list);
  }
  if (isDragging4.value) {
    Object.assign(point4, newPoint);
    RequestRedraw(point4);//请求重绘
    let list = [point1, point2, point3, point4];
    emit("GetCutPosition", list);
  }
};

// 处理鼠标滚轮事件
const onWheel = throttle(function(event) {
  event.preventDefault();

  // 计算新的缩放比例
  if (event.deltaY < 0) {
    // 向上滚动放大
    ZoomIn(event);
  } else {
    ZoomOut(event);
  }
}, 100);//节流 100毫秒内最多执行一次

// 监听窗口大小变化，重新计算表格高度 使用节流防止频繁改变窗口大小导致计算量过大而页面卡顿
const handleResize = throttle(function() {
  // 窗口变化重新计算canvas的宽高
  let { width, height } = mainContainer.value.getBoundingClientRect();
}, 500); // 节流 500 毫秒内最多执行一次

// 暴露方法给父组件
defineExpose({
  FitScreen,
  ClockwiseRotateImage,
  AnticlockwiseRotateImage
});
</script>
<style lang="scss" scoped>
.main_container
{
  position: relative;
  width: 100%;
  height: 100%;
}

#paperCanvas
{
  position: absolute;
  cursor: pointer;
  transition: transform 0.3s ease-in-out;/* 添加平滑过渡效果 */
}
</style>