import { onBeforeUnmount, onMounted, reactive, ref } from "vue";
import { clamp } from "../utils/format.js";

export function useDraggableModal(initialPosition = { x: 190, y: 140 }) {
  const modalRef = ref(null);
  const headerRef = ref(null);

  const state = reactive({
    dragging: false,
    pointerId: null,
    offsetX: 0,
    offsetY: 0,
    x: initialPosition.x,
    y: initialPosition.y,
  });

  const style = reactive({
    left: `${state.x}px`,
    top: `${state.y}px`,
  });

  function clampToViewport() {
    const modal = modalRef.value;
    if (!modal) return;
    const rect = modal.getBoundingClientRect();
    const pad = 10;
    const maxLeft = Math.max(pad, window.innerWidth - rect.width - pad);
    const maxTop = Math.max(pad, window.innerHeight - rect.height - pad);
    state.x = clamp(parseFloat(style.left), pad, maxLeft);
    state.y = clamp(parseFloat(style.top), pad, maxTop);
    style.left = `${state.x}px`;
    style.top = `${state.y}px`;
  }

  function onHeaderPointerDown(e, closeSelector = ".close-btn") {
    if (e.target.closest(closeSelector) || e.button !== 0) return;
    const modal = modalRef.value;
    if (!modal) return;
    state.dragging = true;
    state.pointerId = e.pointerId;
    headerRef.value?.setPointerCapture?.(e.pointerId);
    const rect = modal.getBoundingClientRect();
    state.offsetX = e.clientX - rect.left;
    state.offsetY = e.clientY - rect.top;
  }

  function onWindowPointerMove(e) {
    if (!state.dragging) return;
    if (state.pointerId != null && e.pointerId !== state.pointerId) return;
    const modal = modalRef.value;
    if (!modal) return;
    const rect = modal.getBoundingClientRect();
    const pad = 10;
    const x = clamp(e.clientX - state.offsetX, pad, Math.max(pad, window.innerWidth - rect.width - pad));
    const y = clamp(e.clientY - state.offsetY, pad, Math.max(pad, window.innerHeight - rect.height - pad));
    style.left = `${x}px`;
    style.top = `${y}px`;
  }

  function onWindowPointerUp(e) {
    if (!state.dragging) return;
    if (state.pointerId != null && e.pointerId !== state.pointerId) return;
    state.dragging = false;
    state.pointerId = null;
    clampToViewport();
  }

  onMounted(() => {
    window.addEventListener("pointermove", onWindowPointerMove);
    window.addEventListener("pointerup", onWindowPointerUp);
    window.addEventListener("pointercancel", onWindowPointerUp);
  });

  onBeforeUnmount(() => {
    window.removeEventListener("pointermove", onWindowPointerMove);
    window.removeEventListener("pointerup", onWindowPointerUp);
    window.removeEventListener("pointercancel", onWindowPointerUp);
  });

  function resetPosition(x = initialPosition.x, y = initialPosition.y) {
    state.x = x;
    state.y = y;
    style.left = `${x}px`;
    style.top = `${y}px`;
  }

  return {
    modalRef,
    headerRef,
    state,
    style,
    onHeaderPointerDown,
    resetPosition,
    clampToViewport,
  };
}
