// 弹窗拖动
import { ref, Ref, watch, nextTick, computed } from 'vue';

type posType = {
  top: number;
  left: number;
};

/**
 * @params classList  可拖动地方的class值，也为唯一值
 * @params boxClass  容器class值必须为唯一值，这个class和useid拼接 作为缓存主键
 * @params dragShow  弹窗是否显示
 * @params userId    当前用户id
 */
export default function useDrag(
  classList: string[],
  boxClass: string,
  dragShow: Ref<boolean>,
  userId: string
) {
  const pos = ref<posType>({
    top: -1, // -1 为初始值 代表没有缓存 默认居中
    left: -1
  });
  const useIdDargClass = userId + boxClass;
  watch(dragShow, () => {
    if (dragShow.value) {
      // 初始化pos值
      initPos();
      window.addEventListener('resize', refreshPos);
      nextTick(() => {
        const boxClassDom = document.querySelector(
          `.${boxClass}`
        ) as HTMLElement;
        if (!boxClassDom) {
          return;
        }
        classList.map((className: string) => {
          const classDom = document.querySelector(
            `.${className}`
          ) as HTMLElement;
          if (classDom) {
            classDom.style.cursor = 'move';
            drag(classDom, boxClassDom, pos);
          }
        });
      });
    } else {
      window.removeEventListener('resize', refreshPos);
      setCachePos(useIdDargClass, pos.value);
    }
  });
  const styleDrag = computed(() => {
    // 没有设置拖动的时候保持原本的
    return pos.value.left === -1 && pos.value.top === -1
      ? {}
      : {
          position: 'fixed',
          left: `${pos.value.left}px`,
          top: `${pos.value.top}px`,
          transform: 'initial',
          transformOrigin: 'initial',
          margin: 'initial',
          transition: 'initial'
        };
  });
  function initPos() {
    const posCache = getCachePos(useIdDargClass);
    // 有缓存 用缓存的值，没有缓存用默认
    if (posCache) {
      pos.value = posCache;
      nextTick(() => {
        refreshPos();
      });
    }
  }
  function refreshPos() {
    if (pos.value.left === -1 && pos.value.top === -1) {
      return;
    }
    const boxClassDom = document.querySelector(`.${boxClass}`) as HTMLElement;
    if (!boxClassDom) return;
    const parentElementRect = boxClassDom.getBoundingClientRect();
    const clientWidth = document.documentElement.clientWidth;
    const clientHeight = document.documentElement.clientHeight;
    const { top, left } = pos.value;
    const maxLeft = clientWidth - parentElementRect.width;
    const maxTop = clientHeight - parentElementRect.height;
    let moveX = left;
    let moveY = top;
    const minLeft = 0;
    const minTop = 0;
    moveX = moveX < minLeft ? minLeft : moveX > maxLeft ? maxLeft : moveX;
    moveY = moveY < minTop ? minTop : moveY > maxTop ? maxTop : moveY;
    pos.value = {
      top: moveY,
      left: moveX
    };
  }
  return {
    pos,
    styleDrag
  };
}

// 拖动
function drag(el: HTMLElement, parentElement: HTMLElement, pos: Ref<posType>) {
  function onDown(e: MouseEvent | TouchEvent) {
    const isTouchEv = isTouchEvent(e);
    const event = isTouchEv ? e.touches[0] : e;
    const parentElementRect = parentElement.getBoundingClientRect();
    const downX = event.clientX;
    const downY = event.clientY;
    const clientWidth = document.documentElement.clientWidth;
    const clientHeight = document.documentElement.clientHeight;
    const maxLeft = clientWidth - parentElementRect.width;
    const maxTop = clientHeight - parentElementRect.height;
    const minLeft = 0;
    const minTop = 0;
    function onMove(e: MouseEvent | TouchEvent) {
      const event = isTouchEvent(e) ? e.touches[0] : e;
      let moveX = parentElementRect.left + (event.clientX - downX);
      let moveY = parentElementRect.top + (event.clientY - downY);
      moveX = moveX < minLeft ? minLeft : moveX > maxLeft ? maxLeft : moveX;
      moveY = moveY < minTop ? minTop : moveY > maxTop ? maxTop : moveY;
      pos.value = {
        top: moveY,
        left: moveX
      };
    }
    function onUp() {
      document.removeEventListener(
        isTouchEv ? 'touchmove' : 'mousemove',
        onMove
      );
      document.removeEventListener(isTouchEv ? 'touchend' : 'mouseup', onUp);
    }
    document.addEventListener(isTouchEv ? 'touchmove' : 'mousemove', onMove);
    document.addEventListener(isTouchEv ? 'touchend' : 'mouseup', onUp);
  }
  el.addEventListener('mousedown', onDown);
  el.addEventListener('touchstart', onDown);
}

function isTouchEvent(e: MouseEvent | TouchEvent): e is TouchEvent {
  return window.TouchEvent && e instanceof window.TouchEvent;
}

// 缓存
const localStorageName = 'dragCachePos';
function getCachePos(useIdDargClass: string): null | undefined | posType {
  const localCachePos = localStorage.getItem(localStorageName);
  if (localCachePos) {
    try {
      return JSON.parse(localCachePos)[useIdDargClass];
    } catch {
      return null;
    }
  }
  return null;
}
function setCachePos(useIdDargClass: string, pos: posType) {
  const localCachePos = localStorage.getItem(localStorageName);
  let cachePosObj: Record<string, any> = {};
  if (localCachePos) {
    try {
      cachePosObj = JSON.parse(localCachePos);
    } catch {
      //
    }
  }
  cachePosObj[useIdDargClass] = pos;
  localStorage.setItem(localStorageName, JSON.stringify(cachePosObj));
}
