<template>
  <div
      class="draggable-container"
      :style="containerStyle"
      @mousedown="startDrag"
      @touchstart.prevent="startDrag"
  >
    <slot />
  </div>
</template>

<script setup>
const props = defineProps({
  fixedSide: {
    type: String,
    default: 'none',
    validator: (v) => ['left', 'right', 'top', 'bottom', 'none'].includes(v)
  },
  initialPosition: {
    type: Object,
    default: () => ({ x: 0, y: 0 })
  },
  width: Number,
  height: Number
})

const position = ref({ ...props.initialPosition })
const isDragging = ref(false)
const startPosition = ref({ x: 0, y: 0 })

const containerStyle = computed(() => ({
  position: 'fixed',
  width: props.width ? `${props.width}px` : 'auto',
  height: props.height ? `${props.height}px` : 'auto',
  left: `${position.value.x}px`,
  top: `${position.value.y}px`,
  cursor: isDragging.value ? 'grabbing' : 'grab'
}))

const getClientPos = (e) => ({
  x: e.touches ? e.touches[0].clientX : e.clientX,
  y: e.touches ? e.touches[0].clientY : e.clientY
})

const startDrag = (e) => {
  isDragging.value = true
  const { x, y } = getClientPos(e)
  startPosition.value = {
    x: x - position.value.x,
    y: y - position.value.y
  }
}

const onDrag = (e) => {
  if (!isDragging.value) return

  const { x: clientX, y: clientY } = getClientPos(e)
  const maxX = window.innerWidth - (props.width || 0)
  const maxY = window.innerHeight - (props.height || 0)

  let newX = clientX - startPosition.value.x
  let newY = clientY - startPosition.value.y

  // 根据固定边限制移动方向
  switch (props.fixedSide) {
    case 'left':
      newX = 0
      newY = Math.max(0, Math.min(newY, maxY))
      break
    case 'right':
      newX = maxX
      newY = Math.max(0, Math.min(newY, maxY))
      break
    case 'top':
      newX = Math.max(0, Math.min(newX, maxX))
      newY = 0
      break
    case 'bottom':
      newX = Math.max(0, Math.min(newX, maxX))
      newY = maxY
      break
    default:
      newX = Math.max(0, Math.min(newX, maxX))
      newY = Math.max(0, Math.min(newY, maxY))
  }

  position.value = {
    x: ['top', 'bottom', 'none'].includes(props.fixedSide) ? newX : position.value.x,
    y: ['left', 'right', 'none'].includes(props.fixedSide) ? newY : position.value.y
  }
}

const stopDrag = () => {
  isDragging.value = false
}

// 事件监听
onMounted(() => {
  document.addEventListener('mousemove', onDrag)
  document.addEventListener('mouseup', stopDrag)
  document.addEventListener('touchmove', onDrag)
  document.addEventListener('touchend', stopDrag)
})

onUnmounted(() => {
  document.removeEventListener('mousemove', onDrag)
  document.removeEventListener('mouseup', stopDrag)
  document.removeEventListener('touchmove', onDrag)
  document.removeEventListener('touchend', stopDrag)
})
</script>

<style scoped>
.draggable-container {
  touch-action: none;
  user-select: none;
  z-index: 9999;
}
</style>