<template>
  <div ref="containerRef" class="cropper-container">
    <img
      ref="imageRef"
      :src="props.src"
      alt="cropper image"
      @load="handleImageLoad"
      @mousedown="handleImageMouseDown"
    />

    <!-- 选择框 -->
    <div
      v-if="selection.visible"
      class="selection-box"
      :style="selectionStyle"
      @mousedown="handleSelectionMouseDown"
      @dblclick="handleDoubleClick"
    >
      <!-- 八个控制点 -->
      <div
        v-for="(handle, index) in handles"
        :key="index"
        :class="['resize-handle', handle.position]"
        @mousedown="handleResizeMouseDown($event, handle.position)"
      ></div>
    </div>
  </div>
</template>

<script setup lang="ts">
  import { ref, computed, onMounted, onUnmounted } from 'vue';

  interface SelectionData {
    x: number;
    y: number;
    width: number;
    height: number;
    visible: boolean;
  }

  interface HandlePosition {
    position: string;
  }

  defineOptions({
    name: 'Cropper',
  });

  const props = withDefaults(
    defineProps<{
      src: string;
    }>(),
    {
      src: '',
    }
  );

  const emit = defineEmits<{
    crop: [data: { x: number; y: number; width: number; height: number }];
  }>();

  const containerRef = ref<HTMLDivElement>();
  const imageRef = ref<HTMLImageElement>();

  // 选择框数据
  const selection = ref<SelectionData>({
    x: 0,
    y: 0,
    width: 0,
    height: 0,
    visible: false,
  });

  // 图片尺寸和位置
  const imageRect = ref({
    left: 0,
    top: 0,
    width: 0,
    height: 0,
  });

  // 拖拽状态
  const dragState = ref({
    isDragging: false,
    isResizing: false,
    resizeDirection: '',
    startX: 0,
    startY: 0,
    startSelection: { x: 0, y: 0, width: 0, height: 0 },
  });

  // 控制点配置
  const handles: HandlePosition[] = [
    { position: 'nw' }, // 左上
    { position: 'n' }, // 上
    { position: 'ne' }, // 右上
    { position: 'e' }, // 右
    { position: 'se' }, // 右下
    { position: 's' }, // 下
    { position: 'sw' }, // 左下
    { position: 'w' }, // 左
  ];

  // 选择框样式
  const selectionStyle = computed(() => ({
    left: `${selection.value.x}px`,
    top: `${selection.value.y}px`,
    width: `${selection.value.width}px`,
    height: `${selection.value.height}px`,
  }));

  // 图片加载完成
  function handleImageLoad() {
    updateImageRect();
  }

  // 更新图片位置和尺寸
  function updateImageRect() {
    if (!imageRef.value || !containerRef.value) return;

    const containerRect = containerRef.value.getBoundingClientRect();
    const imgRect = imageRef.value.getBoundingClientRect();

    imageRect.value = {
      left: imgRect.left - containerRect.left,
      top: imgRect.top - containerRect.top,
      width: imgRect.width,
      height: imgRect.height,
    };
  }

  // 图片鼠标按下事件
  function handleImageMouseDown(event: MouseEvent) {
    if (dragState.value.isDragging || dragState.value.isResizing) return;

    event.preventDefault();

    const rect = containerRef.value!.getBoundingClientRect();
    const x = event.clientX - rect.left;
    const y = event.clientY - rect.top;

    // 开始新的选择
    selection.value = {
      x,
      y,
      width: 0,
      height: 0,
      visible: true,
    };

    dragState.value = {
      isDragging: true,
      isResizing: false,
      resizeDirection: '',
      startX: x,
      startY: y,
      startSelection: { ...selection.value },
    };

    document.addEventListener('mousemove', handleMouseMove);
    document.addEventListener('mouseup', handleMouseUp);
  }

  // 选择框鼠标按下事件（移动）
  function handleSelectionMouseDown(event: MouseEvent) {
    if (event.target !== event.currentTarget) return; // 避免控制点事件冒泡

    event.preventDefault();
    event.stopPropagation();

    const rect = containerRef.value!.getBoundingClientRect();
    const x = event.clientX - rect.left;
    const y = event.clientY - rect.top;

    dragState.value = {
      isDragging: true,
      isResizing: false,
      resizeDirection: '',
      startX: x,
      startY: y,
      startSelection: { ...selection.value },
    };

    document.addEventListener('mousemove', handleMouseMove);
    document.addEventListener('mouseup', handleMouseUp);
  }

  // 控制点鼠标按下事件（调整大小）
  function handleResizeMouseDown(event: MouseEvent, direction: string) {
    event.preventDefault();
    event.stopPropagation();

    const rect = containerRef.value!.getBoundingClientRect();
    const x = event.clientX - rect.left;
    const y = event.clientY - rect.top;

    dragState.value = {
      isDragging: false,
      isResizing: true,
      resizeDirection: direction,
      startX: x,
      startY: y,
      startSelection: { ...selection.value },
    };

    document.addEventListener('mousemove', handleMouseMove);
    document.addEventListener('mouseup', handleMouseUp);
  }

  // 鼠标移动事件
  function handleMouseMove(event: MouseEvent) {
    if (!dragState.value.isDragging && !dragState.value.isResizing) return;

    const rect = containerRef.value!.getBoundingClientRect();
    const currentX = event.clientX - rect.left;
    const currentY = event.clientY - rect.top;

    if (dragState.value.isDragging && !dragState.value.isResizing) {
      // 创建新选择或移动选择框
      if (dragState.value.startSelection.width === 0) {
        // 创建新选择
        const width = Math.abs(currentX - dragState.value.startX);
        const height = Math.abs(currentY - dragState.value.startY);
        const x = Math.min(currentX, dragState.value.startX);
        const y = Math.min(currentY, dragState.value.startY);

        selection.value = {
          x: Math.max(
            imageRect.value.left,
            Math.min(x, imageRect.value.left + imageRect.value.width - width)
          ),
          y: Math.max(
            imageRect.value.top,
            Math.min(y, imageRect.value.top + imageRect.value.height - height)
          ),
          width: Math.min(width, imageRect.value.width),
          height: Math.min(height, imageRect.value.height),
          visible: true,
        };
      } else {
        // 移动选择框
        const deltaX = currentX - dragState.value.startX;
        const deltaY = currentY - dragState.value.startY;

        let newX = dragState.value.startSelection.x + deltaX;
        let newY = dragState.value.startSelection.y + deltaY;

        // 边界限制
        newX = Math.max(
          imageRect.value.left,
          Math.min(
            newX,
            imageRect.value.left + imageRect.value.width - selection.value.width
          )
        );
        newY = Math.max(
          imageRect.value.top,
          Math.min(
            newY,
            imageRect.value.top +
              imageRect.value.height -
              selection.value.height
          )
        );

        selection.value.x = newX;
        selection.value.y = newY;
      }
    } else if (dragState.value.isResizing) {
      // 调整选择框大小
      resizeSelection(currentX, currentY);
    }
  }

  // 调整选择框大小
  function resizeSelection(currentX: number, currentY: number) {
    const { startSelection, resizeDirection, startX, startY } = dragState.value;
    const deltaX = currentX - startX;
    const deltaY = currentY - startY;

    let newX = startSelection.x;
    let newY = startSelection.y;
    let newWidth = startSelection.width;
    let newHeight = startSelection.height;

    // 根据拖拽方向调整尺寸
    if (resizeDirection.includes('n')) {
      newY = startSelection.y + deltaY;
      newHeight = startSelection.height - deltaY;
    }
    if (resizeDirection.includes('s')) {
      newHeight = startSelection.height + deltaY;
    }
    if (resizeDirection.includes('w')) {
      newX = startSelection.x + deltaX;
      newWidth = startSelection.width - deltaX;
    }
    if (resizeDirection.includes('e')) {
      newWidth = startSelection.width + deltaX;
    }

    // 最小尺寸限制
    const minSize = 10;
    if (newWidth < minSize) {
      if (resizeDirection.includes('w')) {
        newX = startSelection.x + startSelection.width - minSize;
      }
      newWidth = minSize;
    }
    if (newHeight < minSize) {
      if (resizeDirection.includes('n')) {
        newY = startSelection.y + startSelection.height - minSize;
      }
      newHeight = minSize;
    }

    // 边界限制
    newX = Math.max(
      imageRect.value.left,
      Math.min(newX, imageRect.value.left + imageRect.value.width - newWidth)
    );
    newY = Math.max(
      imageRect.value.top,
      Math.min(newY, imageRect.value.top + imageRect.value.height - newHeight)
    );
    newWidth = Math.min(
      newWidth,
      imageRect.value.left + imageRect.value.width - newX
    );
    newHeight = Math.min(
      newHeight,
      imageRect.value.top + imageRect.value.height - newY
    );

    selection.value.x = newX;
    selection.value.y = newY;
    selection.value.width = newWidth;
    selection.value.height = newHeight;
  }

  // 鼠标抬起事件
  function handleMouseUp() {
    dragState.value.isDragging = false;
    dragState.value.isResizing = false;

    document.removeEventListener('mousemove', handleMouseMove);
    document.removeEventListener('mouseup', handleMouseUp);
  }

  // 双击事件
  function handleDoubleClick() {
    if (!selection.value.visible || !imageRef.value) return;

    // 计算相对于显示图片的坐标
    const relativeX = selection.value.x - imageRect.value.left;
    const relativeY = selection.value.y - imageRect.value.top;

    // 获取图片的原始尺寸和显示尺寸
    const originalWidth = imageRef.value.naturalWidth;
    const originalHeight = imageRef.value.naturalHeight;
    const displayWidth = imageRect.value.width;
    const displayHeight = imageRect.value.height;

    // 计算缩放比例
    const scaleX = originalWidth / displayWidth;
    const scaleY = originalHeight / displayHeight;

    // 转换为原始图片尺寸的坐标
    const originalX = Math.round(relativeX * scaleX);
    const originalY = Math.round(relativeY * scaleY);
    const originalSelectionWidth = Math.round(selection.value.width * scaleX);
    const originalSelectionHeight = Math.round(selection.value.height * scaleY);

    // 计算相对于原图尺寸的相对值（0-1之间），保留4位小数
    const relativeXRatio = parseFloat((originalX / originalWidth).toFixed(4));
    const relativeYRatio = parseFloat((originalY / originalHeight).toFixed(4));
    const relativeWidthRatio = parseFloat(
      (originalSelectionWidth / originalWidth).toFixed(4)
    );
    const relativeHeightRatio = parseFloat(
      (originalSelectionHeight / originalHeight).toFixed(4)
    );

    // 发送裁剪数据（相对于原图尺寸的相对值）
    emit('crop', {
      x: relativeXRatio,
      y: relativeYRatio,
      width: relativeWidthRatio,
      height: relativeHeightRatio,
    });

    // 清空选择
    clearSelection();
  }

  // 清空选择
  function clearSelection() {
    selection.value.visible = false;
    selection.value.x = 0;
    selection.value.y = 0;
    selection.value.width = 0;
    selection.value.height = 0;
  }

  // 暴露方法
  defineExpose({
    clearSelection,
  });

  // 监听窗口大小变化
  function handleResize() {
    updateImageRect();
  }

  onMounted(() => {
    window.addEventListener('resize', handleResize);
  });

  onUnmounted(() => {
    window.removeEventListener('resize', handleResize);
    document.removeEventListener('mousemove', handleMouseMove);
    document.removeEventListener('mouseup', handleMouseUp);
  });
</script>

<style lang="scss" scoped>
  .cropper-container {
    position: relative;
    display: inline-block;
    user-select: none;

    img {
      display: block;
      max-width: 100%;
      max-height: 100%;
      cursor: crosshair;
    }
  }

  .selection-box {
    position: absolute;
    border: 2px dashed #409eff;
    background: rgba(64, 158, 255, 0.2);
    cursor: move;
    box-sizing: border-box;

    &:hover {
      border-color: #66b1ff;
      background: rgba(102, 177, 255, 0.3);
    }
  }

  .resize-handle {
    position: absolute;
    background: #409eff;
    border: 1px solid #fff;
    width: 8px;
    height: 8px;
    border-radius: 50%;

    &:hover {
      background: #66b1ff;
      transform: scale(1.2);
    }

    // 左上角
    &.nw {
      top: -4px;
      left: -4px;
      cursor: nw-resize;
    }

    // 上边中点
    &.n {
      top: -4px;
      left: 50%;
      transform: translateX(-50%);
      cursor: n-resize;
    }

    // 右上角
    &.ne {
      top: -4px;
      right: -4px;
      cursor: ne-resize;
    }

    // 右边中点
    &.e {
      top: 50%;
      right: -4px;
      transform: translateY(-50%);
      cursor: e-resize;
    }

    // 右下角
    &.se {
      bottom: -4px;
      right: -4px;
      cursor: se-resize;
    }

    // 下边中点
    &.s {
      bottom: -4px;
      left: 50%;
      transform: translateX(-50%);
      cursor: s-resize;
    }

    // 左下角
    &.sw {
      bottom: -4px;
      left: -4px;
      cursor: sw-resize;
    }

    // 左边中点
    &.w {
      top: 50%;
      left: -4px;
      transform: translateY(-50%);
      cursor: w-resize;
    }
  }
</style>
