import type { ComputedRef, Ref } from 'vue';

import { onBeforeUnmount, ref, watch } from 'vue';

export function useModalResizable(
  targetRef: Ref<HTMLElement | undefined>,
  resizable: ComputedRef<boolean>,
  containerSelector?: ComputedRef<string | undefined>,
) {
  const resizing = ref(false);
  const handleRef = ref<HTMLElement>();

  function onMousedown(e: MouseEvent) {
    e.preventDefault();
    e.stopPropagation();

    const target = targetRef.value;
    if (!target) return;

    const startX = e.clientX;
    const startY = e.clientY;
    const startWidth = target.offsetWidth;
    const startHeight = target.offsetHeight;
    const startLeft = target.getBoundingClientRect().left;
    const startTop = target.getBoundingClientRect().top;

    resizing.value = true;
    document.body.style.cursor = 'nwse-resize';
    document.body.style.userSelect = 'none';

    const onMousemove = (e: MouseEvent) => {
      const deltaX = e.clientX - startX;
      const deltaY = e.clientY - startY;

      let newWidth = Math.max(startWidth, startWidth + deltaX);
      let newHeight = Math.max(startHeight, startHeight + deltaY);

      if (containerSelector?.value) {
        const container = document.querySelector(containerSelector.value);
        if (container) {
          const containerRect = container.getBoundingClientRect();
          newWidth = Math.min(newWidth, containerRect.right - startLeft);
          newHeight = Math.min(newHeight, containerRect.bottom - startTop);
        }
      } else {
        const docElement = document.documentElement;
        newWidth = Math.min(newWidth, docElement.clientWidth - startLeft);
        newHeight = Math.min(newHeight, docElement.clientHeight - startTop);
      }

      target.style.width = `${newWidth}px`;
      target.style.height = `${newHeight}px`;

      const currentLeft = target.getBoundingClientRect().left;
      const currentTop = target.getBoundingClientRect().top;
      if (currentLeft !== startLeft || currentTop !== startTop) {
        const offsetX = currentLeft - startLeft;
        const offsetY = currentTop - startTop;
        const transform = target.style.transform || '';
        const matchX = transform.match(/translate\(([-\d.]+)px/);
        const matchY = transform.match(/translate\([-\d.]+px,\s*([-\d.]+)px/);
        const currentTranslateX = matchX && matchX[1] ? Number.parseFloat(matchX[1]) : 0;
        const currentTranslateY = matchY && matchY[1] ? Number.parseFloat(matchY[1]) : 0;
        const newTranslateX = currentTranslateX - offsetX;
        const newTranslateY = currentTranslateY - offsetY;
        target.style.transform = `translate(${newTranslateX}px, ${newTranslateY}px)`;
      }
    };

    const onMouseup = () => {
      resizing.value = false;
      document.body.style.cursor = '';
      document.body.style.userSelect = '';
      document.removeEventListener('mousemove', onMousemove);
      document.removeEventListener('mouseup', onMouseup);
    };

    document.addEventListener('mousemove', onMousemove);
    document.addEventListener('mouseup', onMouseup);
  }

  function addHandle() {
    const target = targetRef.value;
    if (!target || handleRef.value) return;

    const handle = document.createElement('div');
    handle.className = 'modal-resize-handle';
    Object.assign(handle.style, {
      position: 'absolute',
      right: '2px',
      bottom: '2px',
      width: '18px',
      height: '18px',
      cursor: 'nwse-resize',
      zIndex: '10',
    });

    handle.addEventListener('mousedown', onMousedown);
    target.append(handle);
    handleRef.value = handle;
  }

  function removeHandle() {
    if (handleRef.value) {
      handleRef.value.removeEventListener('mousedown', onMousedown);
      handleRef.value.remove();
      handleRef.value = undefined;
    }
  }

  function resetSize() {
    const target = targetRef.value;
    if (target) {
      target.style.width = '';
      target.style.height = '';
      target.style.transform = '';
    }
  }

  watch(
    () => targetRef.value,
    (target) => {
      if (target && resizable.value) {
        addHandle();
      } else {
        removeHandle();
      }
    },
    { immediate: true },
  );

  watch(resizable, (val) => {
    if (val && targetRef.value) {
      addHandle();
    } else {
      removeHandle();
    }
  });

  onBeforeUnmount(() => {
    removeHandle();
  });

  return {
    resizing,
    resetSize,
  };
}
