// @ts-nocheck

type ItemsBoxType = {
  getElement: (name: string) => ItemType[];
  getParentSizer: () => ItemsBoxType;
  getChildIndex: (item: ItemType) => number;
  remove: (item: ItemType) => void;
  insert: (index: number, item: ItemType, options: { expand: boolean }) => void;
  getTopmostSizer: () => ItemsBoxType;
};

type CallbackType = (
  event: string,
  callback: (
    pointer?: PointerType,
    dragX?: number,
    dragY?: number,
    dropped?: boolean
  ) => void
) => ItemType;

type PointerType = {
  x: number;
  y: number;
};

type ItemType = {
  on: CallbackType;
  setData: (data: Record<string, unknown>) => ItemType;
  getData: (key: string) => any;
  x: number;
  y: number;
  moveFrom: (options: { x: number; y: number; speed: number }) => void;
};

const AddDragDropItemBehavior = (itemsBox: ItemsBoxType): void => {
  AddDropZone(itemsBox);

  const items: ItemType[] = itemsBox.getElement('items');
  for (const item of items) {
    item
      .on('sizer.dragstart', function () {
        const previousItemsBox = item.getParentSizer();
        item.setData({
          itemsBox: previousItemsBox,
          index: previousItemsBox.getChildIndex(item),
        });
        previousItemsBox.remove(item);
      })
      .on(
        'sizer.dragend',
        function (
          pointer: PointerType,
          dragX: number,
          dragY: number,
          dropped: boolean
        ) {
          if (dropped) {
            return;
          }

          const previousItemsBox = item.getData('itemsBox') as ItemsBoxType;
          previousItemsBox.insert(item.getData('index') as number, item, {
            expand: true,
          });
          ArrangeItems(previousItemsBox);
        }
      )
      .on('sizer.drop', function (pointer: PointerType, dropZone: ItemType) {
        const currentItemsBox = dropZone.getData('itemsBox') as ItemsBoxType;
        const previousItemsBox = item.getData('itemsBox') as ItemsBoxType;

        currentItemsBox.insertAtPosition(pointer.x, pointer.y, item, {
          expand: true,
        });

        ArrangeItems(previousItemsBox, currentItemsBox);
      });
  }
};

type InteractiveItemType = ItemType & {
  setInteractive: (options: { dropZone: boolean }) => void;
};

const AddDropZone = (itemsBox: ItemsBoxType): void => {
  const background = itemsBox.getElement('background') as InteractiveItemType;
  if (background && typeof background.setInteractive === 'function') {
    background.setInteractive({ dropZone: true });
    background.setData('itemsBox', itemsBox);
  } else {
    console.error('Background is not defined or not interactive');
  }
};

const ArrangeItems = (
  itemsBox0: ItemsBoxType,
  itemsBox1?: ItemsBoxType
): void => {
  const items: ItemType[] = [];
  items.push(...itemsBox0.getElement('items'));
  if (itemsBox1 && itemsBox0 !== itemsBox1) {
    items.push(...itemsBox1.getElement('items'));
  }

  for (const item of items) {
    item.setData({ startX: item.x, startY: item.y });
  }

  itemsBox0.getTopmostSizer().layout();

  for (const item of items) {
    const fromX = item.getData('startX') as number;
    const fromY = item.getData('startY') as number;
    if (item.x !== fromX || item.y !== fromY) {
      item.moveFrom({ x: fromX, y: fromY, speed: 300 });
    }
  }
};

export default AddDragDropItemBehavior;
