import { Draggable } from '@shopify/draggable';
import DraggableEvent from './event';

const DRAGGABLE_CLASS = 'draggable-item'
const DRAG_HANDLE_CLASS = 'drag-handle'
const SORTABLE_ATTRIBUTES = ['drag-ignore-handle', 'scrollable'];

const DEFAULT_OPTIONS = {
  draggableClass: DRAGGABLE_CLASS,
  // dragHandleClass: DRAG_HANDLE_CLASS,
  delay: 200,
  tresholdDistance: 2,
  draggable: `.${DRAGGABLE_CLASS}`,
  handle: `.${DRAG_HANDLE_CLASS}`,
  ignoreHandleClassList: SORTABLE_ATTRIBUTES,
  mirror: {
    // appendTo: '.itf-table2 .itf-table2__header',
    yAxis: false,
    constrainDimensions: true
  },
  scrollable: {
    speed: 20,
    sensitivity: 80
  }
};

export default
function createDraggable(options = {}) {
  const draggableNode = new Draggable([], Object.assign({}, DEFAULT_OPTIONS, options));

  return {
    Node: draggableNode,
    dragHandle: {
      inserted(el) {
        if (el.getAttribute('drag-disabled') !== "true") {
          el.classList.add(DRAG_HANDLE_CLASS);
        } else {
          el.classList.remove(DRAG_HANDLE_CLASS);
        }
      },
      update(el) {
        if (el.getAttribute('drag-disabled') !== "true") {
          el.classList.add(DRAG_HANDLE_CLASS);
        } else {
          el.classList.remove(DRAG_HANDLE_CLASS);
        }
      }
    },
    dropzone: {
      inserted(el, {value}) {
        el.over = false;
        el.dropzonePayload = value.payload;
        el.dropCondition = value.condition;

        el.dropzoneDragMove = event => {
          if (el.initialized) {
            return;
          }
          el.initialized = true;
          if (el.getAttribute("accept-group").split(",").includes(event.group)) {
            el.classList.add('active');
            draggableNode.on('drag:move', el.onDragMoveReal);
            el.event = event
          }
        };

        el.onDragMoveReal = event => {
          const { target } = event.sensorEvent;
          if (target === el || el.contains(target)) {
            el.over === false && (!el.dropCondition || el.dropCondition({
              dropzonePayload: el.dropzonePayload,
              draggablePayload: el.event.data.draggablePayload
            })) && (el.dispatchEvent(new Event("enter")), el.classList.add("over"), el.over = !0)
          } else {
            el.over === !0 && (el.dispatchEvent(new Event("leave")), el.classList.remove("over"), el.over = !1);
          }
        };

        el.onDragStop = (event) => {
          if (draggableNode.off('drag:move', el.onDragMoveReal),
            el.classList.remove("active"),
            el.initialized = false,
            !el.over) {
            return;
          }
          el.classList.remove("over");
          el.over = false;
          const detail = {
            ...el.event.data,
            dropzonePayload: el.dropzonePayload,
            newComponent: el
          };
          el.dispatchEvent(new CustomEvent('receive', { detail }));
          el.event.sourceComponent.dispatchEvent(new CustomEvent('drop', { detail }));
        };

        draggableNode.on("vue:drag:move", el.dropzoneDragMove).on("drag:stop", el.onDragStop);
        if (draggableNode.dragging) {
          el.dropzoneDragMove(draggableNode.lastEvent)
        }
      },
      update(el, {value}) {
        el.dropzonePayload = value.payload
      },
      unbind(el) {
        draggableNode.off("vue:drag:move", el.dropzoneDragMove).off("drag:stop", el.onDragStop).off("drag:move", el.onDragMoveReal)
      }
    },
    draggable: {
      inserted(el, {value}) {
        el.currentDraggablePayload = value?.payload;
        el.classList.add(draggableNode.options.draggableClass);
        value?.handle && el.classList.add(draggableNode.options.dragHandleClass);
        value?.mirror && (el.dataset.draggableMirror = JSON.stringify(value.mirror));

        el.onDragStart = event => {
          if (draggableNode.options.ignoreHandleClassList.some(M => event.sensorEvent.target.classList.contains(M))) {
            event.cancel();
            return
          }
          if (el === event.originalEvent.target.closest("." + draggableNode.options.draggableClass)) {
            if (event.originalEvent.target.tagName === "INPUT") {
              event.cancel();
              return
            }
            el.draggablePayload = el.currentDraggablePayload;
            draggableNode.on("drag:move", el.dragMove);
            draggableNode.on("drag:stop", el.dragStop);
            el.dispatchEvent(new Event("drag-start"));
          }
        };

        el.dragMove = () => {
          const event = new DraggableEvent({
            draggablePayload: el.draggablePayload,
            sourceComponent: el,
            group: el.getAttribute("group")
          });
          draggableNode.trigger(event);
          draggableNode.lastEvent = event;
        };

        el.dragStop = () => {
          draggableNode.off("drag:move", el.dragMove);
          draggableNode.off("drag:stop", el.dragStop);
        }
        draggableNode.on("drag:start", el.onDragStart);
      },
      update(el, { value }) {
        el.classList.add(draggableNode.options.draggableClass);
        el.currentDraggablePayload = value?.payload;
        value?.mirror && (el.dataset.draggableMirror = JSON.stringify(value.mirror));
        if (value?.handle) {
          el.classList.add(draggableNode.options.dragHandleClass);
        } else {
          el.classList.remove(draggableNode.options.dragHandleClass);
        }
      },
      unbind(el) {
        draggableNode.off("drag:start", el.onDragStart);
        draggableNode.off("drag:move", el.dragMove);
        draggableNode.off("drag:stop", el.dragStop);
      }
    }
  };
}
