<template>
  <div ref="rndContainer" class="rnd-container" :style="containerStyle">
    <!-- 标题栏 -->
    <div class="float-window-header" @mousedown="handleMouseDown">
      <div v-if="typeof title === 'string'" class="header-title">
        {{ title }}
      </div>
      <div v-else class="header-title-custom">
        <slot name="title">
          {{ title }}
        </slot>
      </div>
      <div class="header-actions">
        <button v-if="onClose" class="close-btn" @click="handleClose">
          <svg-icon icon-class="close" size="20px" />
        </button>
      </div>
    </div>

    <!-- 内容区域 -->
    <div
      ref="contentContainer"
      class="float-window-content"
      @pointerenter="setResizeable(false)"
      @pointerleave="setResizeable(true)"
    >
      <slot />
    </div>

    <!-- 调整大小的手柄 -->
    <div
      v-for="handle in resizeHandles"
      :key="handle"
      :class="`resize-handle resize-handle-${handle}`"
      @mousedown="e => startResize(e, handle)"
    ></div>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, onMounted, onUnmounted, nextTick } from 'vue'
export interface IFloatingWindowProps {
  title?: string | any
  onClose?: () => void
  onResize?: () => void
  minWidth?: number
  minHeight?: number
  defaultSize?: {
    x: number
    y: number
    width: number
    height: number
  }
}

const props = withDefaults(defineProps<IFloatingWindowProps>(), {
  title: '',
  minWidth: 150,
  minHeight: 60
})

const emit = defineEmits<{
  'update:position': [value: { x: number; y: number }]
  'update:size': [value: { width: number; height: number }]
}>()

// 响应式状态
const position = ref({ x: 0, y: 0 })
const size = ref({ width: 400, height: 300 })
const isDragging = ref(false)
const isResizing = ref(false)
const resizeDirection = ref<string | null>(null)
const resizeable = ref(true)
const resizeStart = ref({ x: 0, y: 0, width: 0, height: 0, right: 0, bottom: 0 })
const dragStart = ref({ x: 0, y: 0 })
const containerRef = ref<HTMLElement>()

// 窗口管理
let windowsArrange: HTMLElement[] = []

const focusWindow = (element: HTMLElement) => {
  if (!element) return

  // 过滤掉已经不存在的元素
  windowsArrange = windowsArrange.filter(ele => ele.isConnected && element !== ele)

  // 将当前窗口移到最前面
  windowsArrange.push(element)

  // 更新所有窗口的z-index
  windowsArrange.forEach((ele, index) => {
    ele.style.zIndex = `${index + 3000}`
  })
}

// 计算默认尺寸
const defaultSize = computed(() => {
  if (props.defaultSize) return props.defaultSize

  const width = Math.min(1280, window.innerWidth - 20)
  const height = Math.min(600, window.innerHeight - 20)
  const x = (window.innerWidth - width) / 2
  const y = (window.innerHeight - height) / 2
  return { x, y, width, height }
})

// 容器样式
const containerStyle = computed(() => ({
  position: 'fixed' as const,
  left: `${position.value.x}px`,
  top: `${position.value.y}px`,
  width: `${size.value.width}px`,
  height: `${size.value.height}px`,
  border: '3px solid #43A8AA',
  boxShadow: '3px 3px 20px rgba(0, 0, 0, 0.3)',
  display: 'flex',
  flexDirection: 'column' as const,
  zIndex: '3000',
  backgroundColor: 'var(--color-bg-three)',
  overflow: 'hidden',
  userSelect: (isDragging.value || isResizing.value ? 'none' : 'auto') as any
}))

// 调整大小的手柄位置
const resizeHandles = ['n', 'e', 's', 'w', 'ne', 'nw', 'se', 'sw']

// 事件处理
const handleMouseDown = (e: MouseEvent) => {
  if (!resizeable.value || isResizing.value) return

  isDragging.value = true
  dragStart.value = {
    x: e.clientX - position.value.x,
    y: e.clientY - position.value.y
  }

  if (containerRef.value) {
    focusWindow(containerRef.value)
  }

  document.addEventListener('mousemove', handleDragMove)
  document.addEventListener('mouseup', handleDragEnd)
}

const handleDragMove = (e: MouseEvent) => {
  if (!isDragging.value) return

  let newX = e.clientX - dragStart.value.x
  let newY = e.clientY - dragStart.value.y

  // 边界检查
  newX = Math.max(0, Math.min(newX, window.innerWidth - size.value.width))
  newY = Math.max(0, Math.min(newY, window.innerHeight - size.value.height))

  position.value = { x: newX, y: newY }
  emit('update:position', position.value)
}

const handleDragEnd = () => {
  isDragging.value = false
  document.removeEventListener('mousemove', handleDragMove)
  document.removeEventListener('mouseup', handleDragEnd)
}

const startResize = (e: MouseEvent, direction: string) => {
  if (!resizeable.value) return

  e.stopPropagation()
  e.preventDefault()

  isResizing.value = true
  resizeDirection.value = direction
  resizeStart.value = {
    x: e.clientX,
    y: e.clientY,
    width: size.value.width,
    height: size.value.height,
    right: position.value.x + size.value.width,
    bottom: position.value.y + size.value.height
  }

  document.addEventListener('mousemove', handleResizeMove)
  document.addEventListener('mouseup', handleResizeEnd)
}

const handleResizeMove = (e: MouseEvent) => {
  if (!isResizing.value || !resizeDirection.value) return

  const deltaX = e.clientX - resizeStart.value.x
  const deltaY = e.clientY - resizeStart.value.y

  let newWidth = resizeStart.value.width
  let newHeight = resizeStart.value.height
  let newX = position.value.x
  let newY = position.value.y

  // 根据调整方向计算新尺寸和位置
  switch (resizeDirection.value) {
    // 右边调整 - 固定左边
    case 'e':
      newWidth = Math.max(props.minWidth, resizeStart.value.width + deltaX)
      break

    // 下边调整 - 固定上边
    case 's':
      newHeight = Math.max(props.minHeight, resizeStart.value.height + deltaY)
      break

    // 左边调整 - 固定右边
    case 'w':
      newWidth = Math.max(props.minWidth, resizeStart.value.width - deltaX)
      newX = resizeStart.value.right - newWidth
      break

    // 上边调整 - 固定下边
    case 'n':
      newHeight = Math.max(props.minHeight, resizeStart.value.height - deltaY)
      newY = resizeStart.value.bottom - newHeight
      break

    // 右上角调整 - 固定左下角
    case 'ne':
      newWidth = Math.max(props.minWidth, resizeStart.value.width + deltaX)
      newHeight = Math.max(props.minHeight, resizeStart.value.height - deltaY)
      newY = resizeStart.value.bottom - newHeight
      break

    // 左上角调整 - 固定右下角
    case 'nw':
      newWidth = Math.max(props.minWidth, resizeStart.value.width - deltaX)
      newHeight = Math.max(props.minHeight, resizeStart.value.height - deltaY)
      newX = resizeStart.value.right - newWidth
      newY = resizeStart.value.bottom - newHeight
      break

    // 左下角调整 - 固定右上角
    case 'sw':
      newWidth = Math.max(props.minWidth, resizeStart.value.width - deltaX)
      newHeight = Math.max(props.minHeight, resizeStart.value.height + deltaY)
      newX = resizeStart.value.right - newWidth
      break

    // 右下角调整 - 固定左上角
    case 'se':
    default:
      newWidth = Math.max(props.minWidth, resizeStart.value.width + deltaX)
      newHeight = Math.max(props.minHeight, resizeStart.value.height + deltaY)
      break
  }

  // 边界检查
  newX = Math.max(0, Math.min(newX, window.innerWidth - newWidth))
  newY = Math.max(0, Math.min(newY, window.innerHeight - newHeight))
  newWidth = Math.min(newWidth, window.innerWidth - newX)
  newHeight = Math.min(newHeight, window.innerHeight - newY)

  size.value = { width: newWidth, height: newHeight }
  position.value = { x: newX, y: newY }

  emit('update:size', size.value)
  emit('update:position', position.value)
}

const handleResizeEnd = () => {
  isResizing.value = false
  resizeDirection.value = null
  document.removeEventListener('mousemove', handleResizeMove)
  document.removeEventListener('mouseup', handleResizeEnd)

  props.onResize?.()
}

const setResizeable = (value: boolean) => {
  resizeable.value = value
}

const handleClose = () => props.onClose?.()

// 初始化
onMounted(() => {
  position.value = { x: defaultSize.value.x, y: defaultSize.value.y }
  size.value = { width: defaultSize.value.width, height: defaultSize.value.height }

  nextTick(() => {
    if (containerRef.value) {
      focusWindow(containerRef.value)
    }
  })
})

onUnmounted(() => {
  // 清理事件监听
  document.removeEventListener('mousemove', handleDragMove)
  document.removeEventListener('mouseup', handleDragEnd)
  document.removeEventListener('mousemove', handleResizeMove)
  document.removeEventListener('mouseup', handleResizeEnd)

  // 从窗口管理数组中移除
  if (containerRef.value) {
    windowsArrange = windowsArrange.filter(ele => ele !== containerRef.value)
  }
})
</script>

<style scoped>
.rnd-container {
  box-sizing: border-box;
}

.float-window-header {
  background-color: #1976d2;
  color: white;
  height: 36px;
  display: flex;
  align-items: center;
  padding: 0 5px;
  user-select: none;
  cursor: move;
  flex-shrink: 0;
}

.header-title {
  font-size: 18px;
  font-weight: 800;
  flex-grow: 1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.header-title-custom {
  flex-grow: 1;
}

.header-actions {
  display: flex;
  align-items: center;
}

.close-btn {
  background: none;
  border: none;
  color: white;
  cursor: pointer;
  width: 24px;
  height: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 4px;
  transition: background-color 0.2s;
}

.close-btn:hover {
  background-color: rgba(255, 255, 255, 0.1);
}

.close-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.float-window-content {
  flex-grow: 1;
  background: var(--color-card);
  overflow: auto;
  position: relative;
}

/* 调整大小的手柄样式 */
.resize-handle {
  position: absolute;
  z-index: 10;
}

.resize-handle-n,
.resize-handle-s {
  width: 100%;
  height: 6px;
  cursor: ns-resize;
}

.resize-handle-e,
.resize-handle-w {
  width: 6px;
  height: 100%;
  cursor: ew-resize;
}

.resize-handle-ne,
.resize-handle-nw,
.resize-handle-se,
.resize-handle-sw {
  width: 12px;
  height: 12px;
}

.resize-handle-n {
  top: -3px;
  left: 0;
}

.resize-handle-s {
  bottom: -3px;
  left: 0;
}

.resize-handle-e {
  top: 0;
  right: -3px;
}

.resize-handle-w {
  top: 0;
  left: -3px;
}

.resize-handle-ne {
  top: -6px;
  right: -6px;
  cursor: ne-resize;
}

.resize-handle-nw {
  top: -6px;
  left: -6px;
  cursor: nw-resize;
}

.resize-handle-se {
  bottom: -6px;
  right: -6px;
  cursor: se-resize;
}

.resize-handle-sw {
  bottom: -6px;
  left: -6px;
  cursor: sw-resize;
}
</style>
