import { cloneDeep } from 'lodash';
import { ComputedRef, ModelRef } from 'vue';

export function useDragAndDrop(items: ComputedRef<Array<any>> | ModelRef<Array<any>>, itemSelector: string, onUpdate: (items: any[]) => void, idKey = 'code') {
  function handler() {
    return true;
  }

  function onDragStart(e) {
    e.dataTransfer.setData('id', e.target.id);
    e.dataTransfer.dropEffect = 'move';
  }

  function onDragLeave(e) {
    e.preventDefault();
    if (!e.target) return;
    const target = e.target.closest(itemSelector);
    if (!target) return;
    if (!target?.contains(e.relatedTarget)) {
      target.classList.remove('drag-enter');
    }
  }

  function onDragOver(e) {
    e.preventDefault();
    if (!e.target) return;
    const target = e.target.closest(itemSelector);
    if (!target) return;
    target.classList.add('drag-enter');
  }

  function onDrop(e) {
    e.preventDefault();
    const target = e.target.closest(itemSelector);
    removeDragClassFromAllItems(target);
    if (!target.draggable) {
      return;
    }
    const draggedId = e.dataTransfer.getData('id');
    if (!target) return;
    const targetId = target?.id ?? null;
    if (targetId === null) return;
    const _items = cloneDeep(items.value);
    const draggedIndex = _items.findIndex((w) => w[idKey] == draggedId);
    const targetIndex = _items.findIndex((w) => w[idKey] == targetId);
    if (draggedIndex === -1 || targetIndex === -1) return;
    const [draggedItem] = _items.splice(draggedIndex, 1);
    _items.splice(targetIndex, 0, draggedItem);
    onUpdate(_items);
  }

  function removeDragClassFromAllItems(target: HTMLElement) {
    const parent = target.parentElement;
    if (!parent) return;
    const children = parent.children;
    for (let i = 0; i < children.length; i++) {
      children[i].classList.remove('drag-enter');
    }
  }

  return { handler, onDragLeave, onDragStart, onDragOver, onDrop };
}
