import { find } from "../../native-with-fallback";
import getDidStartAfterCritical from "../did-start-after-critical";
import getDisplacedBy from "../get-displaced-by";
import getIsDisplaced from "../get-is-displaced";
import removeDraggableFromList from "../remove-draggable-from-list";
// exported for testing
export const combineThresholdDivisor = 4;

const getCombineImpact = ({
  draggable,
  pageBorderBoxWithDroppableScroll: targetRect,
  previousImpact,
  destination,
  insideDestination,
  afterCritical
}) => {
  if (!destination.isCombineEnabled) {
    return null;
  }
  const axis = destination.axis;
  const displacedBy = getDisplacedBy(destination.axis, draggable.displaceBy);
  const displacement = displacedBy.value;
  const targetStart = targetRect[axis.start];
  const targetEnd = targetRect[axis.end];
  const withoutDragging = removeDraggableFromList(draggable, insideDestination);
  const combineWith = find(withoutDragging, (child) => {
    const id = child.descriptor.id;
    const childRect = child.page.borderBox;
    const childSize = childRect[axis.size];
    const threshold = childSize / combineThresholdDivisor;
    const didStartAfterCritical = getDidStartAfterCritical(id, afterCritical);
    const isDisplaced = getIsDisplaced({
      displaced: previousImpact.displaced,
      id
    });

    /*
      Only combining when in the combine region
      As soon as a boundary is hit then no longer combining
    */

    if (didStartAfterCritical) {
      // In original position
      // Will combine with item when inside a band
      if (isDisplaced) {
        return targetEnd > childRect[axis.start] + threshold && targetEnd < childRect[axis.end] - threshold;
      }

      // child is now 'displaced' backwards from where it started
      // want to combine when we move backwards onto it
      return (
        targetStart > childRect[axis.start] - displacement + threshold &&
        targetStart < childRect[axis.end] - displacement - threshold
      );
    }

    // item has moved forwards
    if (isDisplaced) {
      return (
        targetEnd > childRect[axis.start] + displacement + threshold &&
        targetEnd < childRect[axis.end] + displacement - threshold
      );
    }

    // is in resting position - being moved backwards on to
    return targetStart > childRect[axis.start] + threshold && targetStart < childRect[axis.end] - threshold;
  });

  if (!combineWith) {
    return null;
  }

  return {
    // no change to displacement when combining
    displacedBy,
    displaced: previousImpact.displaced,
    at: {
      type: "COMBINE",
      combine: {
        draggableId: combineWith.descriptor.id,
        droppableId: destination.descriptor.id
      }
    }
  };
};

export default getCombineImpact;
