<template>
  <div
    ref="el"
    class="rest-draggable-resizable"
    :class="{ active: active }"
    :style="style"
    @mousedown.stop="handleMouseDown"
    @touchstart.stop="handleTouchStart"
  >
    <slot></slot>
    <div
      v-for="handle in handles"
      :key="handle"
      class="handle"
      :class="`handle-${handle}`"
      @mousedown.stop.prevent="handleResizeStart(handle, $event)"
      @touchstart.stop.prevent="handleResizeTouchStart(handle, $event)"
    ></div>
  </div>
</template>

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

const props = defineProps({
  x: { type: Number, required: true },
  y: { type: Number, required: true },
  w: { type: Number, required: true },
  h: { type: Number, required: true },
  minW: { type: Number, default: 20 },
  minH: { type: Number, default: 20 },
  active: { type: Boolean, default: false },
  draggable: { type: Boolean, default: true },
  resizable: { type: Boolean, default: true },
  parent: { type: [Boolean, Object], default: false }, // boolean or HTMLElement
  handles: {
    type: Array,
    default: () => ['tl', 'tm', 'tr', 'mr', 'br', 'bm', 'bl', 'ml'],
  },
});

const emit = defineEmits([
  'update:x',
  'update:y',
  'update:w',
  'update:h',
  'activated',
  'deactivated',
  'dragging',
  'resizing',
  'drag-end',
  'resize-end',
]);

const el = ref<HTMLElement | null>(null);
const active = ref(props.active);
const zIndex = ref(1);

const style = computed(() => ({
  left: `${props.x}px`,
  top: `${props.y}px`,
  width: `${props.w}px`,
  height: `${props.h}px`,
  zIndex: zIndex.value,
  position: 'absolute' as const,
}));

// State
let isDragging = false;
let isResizing = false;
let startX = 0;
let startY = 0;
let startLeft = 0;
let startTop = 0;
let startWidth = 0;
let startHeight = 0;
let currentHandle = '';

// Parent limits
const parentWidth = ref(0);
const parentHeight = ref(0);

watch(
  () => props.active,
  (val) => {
    active.value = val;
    if (val) emit('activated');
    else emit('deactivated');
  }
);

function getParentSize() {
  if (props.parent && el.value?.parentElement) {
    // If parent prop is an element, use it, otherwise use direct parent
    const parentEl = (props.parent instanceof HTMLElement ? props.parent : el.value.parentElement);
    parentWidth.value = parentEl.clientWidth;
    parentHeight.value = parentEl.clientHeight;
  }
}

// Dragging
function handleMouseDown(e: MouseEvent) {
  if (!props.draggable) return;
  
  // Clicked on handle? handled by handleResizeStart
  // But this is on the main div, so it should be fine due to stop propagation on handles?
  // Wait, handles have @mousedown.stop.prevent, so this won't fire for handles.
  
  // Activate
  if (!active.value) {
    active.value = true;
    emit('activated');
  }

  isDragging = true;
  startX = e.clientX;
  startY = e.clientY;
  startLeft = props.x;
  startTop = props.y;
  
  getParentSize();

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

function handleMouseMove(e: MouseEvent) {
  if (isDragging) {
    let dx = e.clientX - startX;
    let dy = e.clientY - startY;
    
    let newLeft = startLeft + dx;
    let newTop = startTop + dy;
    
    // Constraints
    if (props.parent) {
      if (newLeft < 0) newLeft = 0;
      if (newTop < 0) newTop = 0;
      if (newLeft + props.w > parentWidth.value) newLeft = parentWidth.value - props.w;
      if (newTop + props.h > parentHeight.value) newTop = parentHeight.value - props.h;
    }

    emit('update:x', newLeft);
    emit('update:y', newTop);
    emit('dragging', newLeft, newTop);
  }
}

function handleMouseUp() {
  if (isDragging) {
    isDragging = false;
    emit('drag-end');
    window.removeEventListener('mousemove', handleMouseMove);
    window.removeEventListener('mouseup', handleMouseUp);
  }
}

// Resizing
function handleResizeStart(handle: string, e: MouseEvent) {
  if (!props.resizable) return;
  
  isResizing = true;
  currentHandle = handle;
  startX = e.clientX;
  startY = e.clientY;
  startLeft = props.x;
  startTop = props.y;
  startWidth = props.w;
  startHeight = props.h;
  
  getParentSize();

  window.addEventListener('mousemove', handleResizeMove);
  window.addEventListener('mouseup', handleResizeUp);
}

function handleResizeMove(e: MouseEvent) {
  if (isResizing) {
    const dx = e.clientX - startX;
    const dy = e.clientY - startY;
    
    let newLeft = startLeft;
    let newTop = startTop;
    let newWidth = startWidth;
    let newHeight = startHeight;
    
    if (currentHandle.includes('r')) {
      newWidth = startWidth + dx;
    }
    if (currentHandle.includes('l')) {
      newWidth = startWidth - dx;
      newLeft = startLeft + dx;
    }
    if (currentHandle.includes('b')) {
      newHeight = startHeight + dy;
    }
    if (currentHandle.includes('t')) {
      newHeight = startHeight - dy;
      newTop = startTop + dy;
    }
    
    // Min size
    if (newWidth < props.minW) {
      newWidth = props.minW;
      if (currentHandle.includes('l')) newLeft = startLeft + startWidth - props.minW;
    }
    if (newHeight < props.minH) {
      newHeight = props.minH;
      if (currentHandle.includes('t')) newTop = startTop + startHeight - props.minH;
    }
    
    // Parent constraints
    if (props.parent) {
      if (newLeft < 0) {
        newWidth += newLeft;
        newLeft = 0;
      }
      if (newTop < 0) {
        newHeight += newTop;
        newTop = 0;
      }
      if (newLeft + newWidth > parentWidth.value) {
        newWidth = parentWidth.value - newLeft;
      }
      if (newTop + newHeight > parentHeight.value) {
        newHeight = parentHeight.value - newTop;
      }
    }

    emit('update:x', newLeft);
    emit('update:y', newTop);
    emit('update:w', newWidth);
    emit('update:h', newHeight);
    emit('resizing', newLeft, newTop, newWidth, newHeight);
  }
}

function handleResizeUp() {
  if (isResizing) {
    isResizing = false;
    emit('resize-end');
    window.removeEventListener('mousemove', handleResizeMove);
    window.removeEventListener('mouseup', handleResizeUp);
  }
}

// Touch support (basic)
function handleTouchStart(e: TouchEvent) {
  // Simplified: treat first touch as mouse down
  if (e.touches.length > 0) {
    const touch = e.touches[0];
    handleMouseDown({
      clientX: touch.clientX,
      clientY: touch.clientY,
    } as MouseEvent);
  }
}

function handleResizeTouchStart(handle: string, e: TouchEvent) {
  if (e.touches.length > 0) {
    const touch = e.touches[0];
    handleResizeStart(handle, {
      clientX: touch.clientX,
      clientY: touch.clientY,
    } as MouseEvent);
  }
}

// Global click to deactivate
function handleGlobalClick(e: MouseEvent) {
  if (el.value && !el.value.contains(e.target as Node)) {
    if (active.value) {
      active.value = false;
      emit('deactivated');
    }
  }
}

onMounted(() => {
  window.addEventListener('mousedown', handleGlobalClick);
});

onBeforeUnmount(() => {
  window.removeEventListener('mousedown', handleGlobalClick);
  window.removeEventListener('mousemove', handleMouseMove);
  window.removeEventListener('mouseup', handleMouseUp);
  window.removeEventListener('mousemove', handleResizeMove);
  window.removeEventListener('mouseup', handleResizeUp);
});
</script>

<style scoped>
.rest-draggable-resizable {
  position: absolute;
  box-sizing: border-box;
  touch-action: none;
}

.rest-draggable-resizable.active {
  border: 1px dashed var(--primary-color, #1890ff);
  z-index: 10 !important;
}

.handle {
  position: absolute;
  width: 8px;
  height: 8px;
  background: #fff;
  border: 1px solid var(--primary-color, #1890ff);
  box-shadow: 0 0 2px rgba(0, 0, 0, 0.1);
  display: none;
  z-index: 11;
}

.active .handle {
  display: block;
}

.handle-tl { top: -4px; left: -4px; cursor: nw-resize; }
.handle-tm { top: -4px; left: 50%; margin-left: -4px; cursor: n-resize; }
.handle-tr { top: -4px; right: -4px; cursor: ne-resize; }
.handle-mr { top: 50%; right: -4px; margin-top: -4px; cursor: e-resize; }
.handle-br { bottom: -4px; right: -4px; cursor: se-resize; }
.handle-bm { bottom: -4px; left: 50%; margin-left: -4px; cursor: s-resize; }
.handle-bl { bottom: -4px; left: -4px; cursor: sw-resize; }
.handle-ml { top: 50%; left: -4px; margin-top: -4px; cursor: w-resize; }
</style>
