import type { Directive, DirectiveBinding } from 'vue';

interface Position {
  x: number;
  y: number;
}

interface DragCallbackParams {
  x: number;
  y: number;
}

interface DragBindingValue {
  onDrag?: (params: DragCallbackParams) => void;
  onStop?: (params: DragCallbackParams) => void;
}

interface DraggableElement extends HTMLElement {
  _mousedownHandler?: (e: MouseEvent) => void;
  _touchstartHandler?: (e: TouchEvent) => void;
  _mousemoveHandler?: (e: MouseEvent) => void;
  _mouseupHandler?: (e: MouseEvent) => void;
  _touchmoveHandler?: (e: TouchEvent) => void;
  _touchendHandler?: (e: TouchEvent) => void;
}

const draggable: Directive<DraggableElement, DragBindingValue> = {
  mounted(el: DraggableElement, binding: DirectiveBinding<DragBindingValue>) {
    let startPosition: Position = { x: 0, y: 0 };
    let dialogPosition: Position = { x: 0, y: 0 };
    let dragging = false;
    let isClick = false;

    const handleStart = (x: number, y: number) => {
      startPosition.x = x;
      startPosition.y = y;
      // 获取当前元素的位置，如果之前没有设置过则默认为0
      const style = window.getComputedStyle(el);
      dialogPosition.x = parseInt(style.left, 10) || 0;
      dialogPosition.y = parseInt(style.top, 10) || 0;
      dragging = false;
      isClick = true;
    };

    const handleMove = (x: number, y: number) => {
      if (!dragging) {
        const moveDistance = Math.sqrt(
          Math.pow(x - startPosition.x, 2) + 
          Math.pow(y - startPosition.y, 2)
        );
        
        // 移动距离超过5px视为拖拽
        if (moveDistance > 5) {
          dragging = true;
          isClick = false;
        }
      }
      
      if (dragging) {
        const offsetX = x - startPosition.x;
        const offsetY = y - startPosition.y;
        el.style.left = `${dialogPosition.x + offsetX}px`;
        el.style.top = `${dialogPosition.y + offsetY}px`;
        
        // 触发拖拽中回调
        if (binding.value && typeof binding.value === 'object' && binding.value.onDrag) {
          binding.value.onDrag({
            x: dialogPosition.x + offsetX,
            y: dialogPosition.y + offsetY
          });
        }
      }
    };

    const handleEnd = (e: Event) => {
      // 触发停止回调
      if (binding.value && typeof binding.value === 'object' && binding.value.onStop) {
        const finalLeft = parseInt(el.style.left, 10) || 0;
        const finalTop = parseInt(el.style.top, 10) || 0;
        binding.value.onStop({
          x: finalLeft,
          y: finalTop
        });
      }
      
      dragging = false;
      isClick = false;
    };

    // 鼠标事件处理函数
    const handleMouseDown = (e: MouseEvent) => {
      e.stopPropagation();
      // 只有点击在标题栏或特定区域才允许拖拽，这里假设整个el都可以拖拽
      // 如果需要限制拖拽手柄，可以判断 e.target
      handleStart(e.clientX, e.clientY);
      document.addEventListener('mousemove', handleMouseMove);
      document.addEventListener('mouseup', handleMouseUp);
    };

    const handleMouseMove = (e: MouseEvent) => {
      handleMove(e.clientX, e.clientY);
      if (dragging) {
        e.preventDefault();
        e.stopPropagation();
      }
    };

    const handleMouseUp = (e: MouseEvent) => {
      document.removeEventListener('mousemove', handleMouseMove);
      document.removeEventListener('mouseup', handleMouseUp);
      handleEnd(e);
    };

    // 触摸事件处理函数
    const handleTouchStart = (e: TouchEvent) => {
      if (e.touches.length > 0) {
        e.stopPropagation();
        const touch = e.touches[0];
        handleStart(touch.clientX, touch.clientY);
        document.addEventListener('touchmove', handleTouchMove, { passive: false });
        document.addEventListener('touchend', handleTouchEnd);
      }
    };

    const handleTouchMove = (e: TouchEvent) => {
      if (e.touches.length > 0) {
        e.preventDefault(); // 阻止页面滚动
        e.stopPropagation();
        const touch = e.touches[0];
        handleMove(touch.clientX, touch.clientY);
      }
    };

    const handleTouchEnd = (e: TouchEvent) => {
      document.removeEventListener('touchmove', handleTouchMove);
      document.removeEventListener('touchend', handleTouchEnd);
      handleEnd(e);
    };

    // 绑定事件并保存引用以便卸载时清理
    el._mousedownHandler = handleMouseDown;
    el._touchstartHandler = handleTouchStart;
    el._mousemoveHandler = handleMouseMove;
    el._mouseupHandler = handleMouseUp;
    el._touchmoveHandler = handleTouchMove;
    el._touchendHandler = handleTouchEnd;

    el.addEventListener('mousedown', handleMouseDown);
    el.addEventListener('touchstart', handleTouchStart, { passive: false });
  },
  
  beforeUnmount(el: DraggableElement) {
    // 清理事件监听器，防止内存泄漏
    if (el._mousedownHandler) {
      el.removeEventListener('mousedown', el._mousedownHandler);
      delete el._mousedownHandler;
    }
    if (el._touchstartHandler) {
      el.removeEventListener('touchstart', el._touchstartHandler);
      delete el._touchstartHandler;
    }
    if (el._mousemoveHandler) {
      document.removeEventListener('mousemove', el._mousemoveHandler);
      delete el._mousemoveHandler;
    }
    if (el._mouseupHandler) {
      document.removeEventListener('mouseup', el._mouseupHandler);
      delete el._mouseupHandler;
    }
    if (el._touchmoveHandler) {
      document.removeEventListener('touchmove', el._touchmoveHandler);
      delete el._touchmoveHandler;
    }
    if (el._touchendHandler) {
      document.removeEventListener('touchend', el._touchendHandler);
      delete el._touchendHandler;
    }
  }
};

export default draggable;