import { invariant } from "../../../../invariant";
import { tryGetDestination } from "../../../get-impact-location";
import { findIndex } from "../../../../native-with-fallback";
import removeDraggableFromList from "../../../remove-draggable-from-list";

const moveToNextCombine = ({ isMovingForward, draggable, destination, insideDestination, previousImpact }) => {
  if (!destination.isCombineEnabled) {
    return null;
  }
  const location = tryGetDestination(previousImpact);
  if (!location) {
    return null;
  }

  function getImpact(target) {
    const at = {
      type: "COMBINE",
      combine: {
        draggableId: target,
        droppableId: destination.descriptor.id
      }
    };
    return {
      ...previousImpact,
      at
    };
  }

  const all = previousImpact.displaced.all;
  const closestId = all.length ? all[0] : null;
  if (isMovingForward) {
    return closestId ? getImpact(closestId) : null;
  }
  const withoutDraggable = removeDraggableFromList(draggable, insideDestination);

  // Moving backwards

  // if nothing is displaced - move backwards onto the last item
  if (!closestId) {
    if (!withoutDraggable.length) {
      return null;
    }
    const last = withoutDraggable[withoutDraggable.length - 1];
    return getImpact(last.descriptor.id);
  }

  // We are moving from being between two displaced items
  // backwards onto the first one

  // need to find the first item before the closest
  const indexOfClosest = findIndex(withoutDraggable, (d) => d.descriptor.id === closestId);
  invariant(indexOfClosest !== -1, "Could not find displaced item in set");
  const proposedIndex = indexOfClosest - 1;

  // There is no displaced item before
  if (proposedIndex < 0) {
    return null;
  }
  const before = withoutDraggable[proposedIndex];
  return getImpact(before.descriptor.id);
};

export default moveToNextCombine;
