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

interface ResizableElement extends HTMLElement {
  __modal_resizable__?: {
    handleEl: HTMLElement;
    initialHeight?: number;
    initialWidth?: number;
    onMousedown: (e: MouseEvent) => void;
    styleObserver: MutationObserver;
  };
}

const RESIZABLE_KEY = '__modal_resizable__' as const;

function resetModalSize(modalWrap: ResizableElement) {
  const dragDom = modalWrap.querySelector('.ant-modal') as HTMLElement;
  const modalContent = modalWrap.querySelector('.ant-modal-content') as HTMLElement;
  if (dragDom) {
    dragDom.style.width = '';
    dragDom.style.left = '';
    dragDom.style.top = '';
  }
  if (modalContent) {
    modalContent.style.height = '';
    modalContent.classList.remove('is-modal-resized');
  }
  const resizeData = modalWrap[RESIZABLE_KEY];
  if (resizeData) {
    resizeData.initialWidth = undefined;
    resizeData.initialHeight = undefined;
  }
}

function setupResize(modalWrap: ResizableElement) {
  const dragDom = modalWrap.querySelector('.ant-modal') as HTMLElement;
  const modalContent = modalWrap.querySelector('.ant-modal-content') as HTMLElement;

  if (!dragDom || !modalContent) return;
  if (modalWrap[RESIZABLE_KEY]) return;
  if (modalWrap.classList.contains('fullscreen-modal')) return;
  if (dragDom.classList.contains('ant-modal-confirm')) return;

  const handleEl = document.createElement('div');
  handleEl.className = 'modal-resize-handle';
  modalContent.append(handleEl);

  const styleObserver = new MutationObserver(() => {
    if (modalWrap.style.display === 'none') {
      resetModalSize(modalWrap);
    }
  });
  styleObserver.observe(modalWrap, { attributes: true, attributeFilter: ['style'] });

  const onMousedown = (e: MouseEvent) => {
    if (!e) return;
    e.preventDefault();
    e.stopPropagation();

    const resizeData = modalWrap[RESIZABLE_KEY];
    if (!resizeData) return;
    if (!resizeData.initialWidth || !resizeData.initialHeight) {
      resizeData.initialWidth = dragDom.offsetWidth;
      resizeData.initialHeight = dragDom.offsetHeight;
    }

    const startX = e.clientX;
    const startY = e.clientY;
    const startWidth = dragDom.offsetWidth;
    const startHeight = dragDom.offsetHeight;
    const minWidth = resizeData.initialWidth;
    const minHeight = resizeData.initialHeight;
    const startLeft = dragDom.getBoundingClientRect().left;
    const startTop = dragDom.getBoundingClientRect().top;

    const screenWidth = document.body.clientWidth;
    const screenHeight = document.documentElement.clientHeight;

    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(minWidth, startWidth + deltaX);
      let newHeight = Math.max(minHeight, startHeight + deltaY);

      newWidth = Math.min(newWidth, screenWidth - startLeft);
      newHeight = Math.min(newHeight, screenHeight - startTop);

      modalContent.classList.add('is-modal-resized');
      dragDom.style.width = `${newWidth}px`;
      modalContent.style.height = `${newHeight}px`;

      const currentLeft = dragDom.getBoundingClientRect().left;
      if (currentLeft !== startLeft) {
        const offset = currentLeft - startLeft;
        const currentStyleLeft = Number.parseFloat(getComputedStyle(dragDom).left) || 0;
        dragDom.style.left = `${currentStyleLeft - offset}px`;
      }

      const currentTop = dragDom.getBoundingClientRect().top;
      if (currentTop !== startTop) {
        const offset = currentTop - startTop;
        const currentStyleTop = Number.parseFloat(getComputedStyle(dragDom).top) || 0;
        dragDom.style.top = `${currentStyleTop - offset}px`;
      }
    };

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

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

  handleEl.addEventListener('mousedown', onMousedown);
  (modalWrap as ResizableElement)[RESIZABLE_KEY] = { handleEl, onMousedown, styleObserver };
}

function cleanupResize(modalWrap: ResizableElement) {
  const resizeData = modalWrap[RESIZABLE_KEY];
  if (resizeData) {
    resizeData.handleEl.removeEventListener('mousedown', resizeData.onMousedown);
    resizeData.handleEl.remove();
    resizeData.styleObserver.disconnect();
    resetModalSize(modalWrap);
    delete modalWrap[RESIZABLE_KEY];
  }
}

/** 自动为所有 .ant-modal-wrap 添加 resize 支持 */
export function setupGlobalResizeObserver() {
  const observer = new MutationObserver((mutations) => {
    for (const mutation of mutations) {
      for (const node of mutation.addedNodes) {
        if (node instanceof HTMLElement) {
          if (node.classList.contains('ant-modal-wrap')) {
            setTimeout(() => setupResize(node as ResizableElement), 50);
          }
          const wraps = node.querySelectorAll?.('.ant-modal-wrap');
          wraps?.forEach((wrap) => {
            setTimeout(() => setupResize(wrap as ResizableElement), 50);
          });
        }
      }
      for (const node of mutation.removedNodes) {
        if (node instanceof HTMLElement) {
          if (node.classList.contains('ant-modal-wrap')) {
            cleanupResize(node as ResizableElement);
          }
          const wraps = node.querySelectorAll?.('.ant-modal-wrap');
          wraps?.forEach((wrap) => cleanupResize(wrap as ResizableElement));
        }
      }
    }
  });

  observer.observe(document.body, { childList: true, subtree: true });
  return observer;
}

/** v-resizable 指令，用于显式标记需要 resize 的 modal */
export const vResizable: Directive = {
  mounted(el: HTMLElement) {
    const modalWrap = (el.classList.contains('ant-modal-wrap') ? el : el.closest('.ant-modal-wrap')) as ResizableElement;
    if (!modalWrap) return;

    const observer = new MutationObserver(() => {
      const dragDom = modalWrap.querySelector('.ant-modal');
      if (dragDom) {
        observer.disconnect();
        setupResize(modalWrap);
      }
    });

    observer.observe(modalWrap, { childList: true, subtree: true });

    if (modalWrap.querySelector('.ant-modal')) {
      observer.disconnect();
      setupResize(modalWrap);
    }
  },

  unmounted(el: HTMLElement) {
    const modalWrap = (el.classList.contains('ant-modal-wrap') ? el : el.closest('.ant-modal-wrap')) as ResizableElement;
    if (!modalWrap) return;
    cleanupResize(modalWrap);
  },
};

/** 全局注册指令和自动 resize */
export function registerResizable(app: App) {
  app.directive('resizable', vResizable);
  setupGlobalResizeObserver();
}
