import scrollViewport from "../scroll-viewport";
import scrollDroppable from "../droppable/scroll-droppable";
import { add } from "../position";
import getDisplacementGroups from "../get-displacement-groups";

function getDraggables(ids, draggables) {
  return ids.map((id) => draggables[id]);
}

function tryGetVisible(id, groups) {
  for (let i = 0; i < groups.length; i++) {
    const displacement = groups[i].visible[id];
    if (displacement) {
      return displacement;
    }
  }
  return null;
}

const speculativelyIncrease = ({ impact, viewport, destination, draggables, maxScrollChange }) => {
  const scrolledViewport = scrollViewport(viewport, add(viewport.scroll.current, maxScrollChange));
  const scrolledDroppable = destination.frame
    ? scrollDroppable(destination, add(destination.frame.scroll.current, maxScrollChange))
    : destination;
  const last = impact.displaced;
  const withViewportScroll = getDisplacementGroups({
    afterDragging: getDraggables(last.all, draggables),
    destination,
    displacedBy: impact.displacedBy,
    viewport: scrolledViewport.frame,
    last,
    // we want the addition to be animated
    forceShouldAnimate: false
  });
  const withDroppableScroll = getDisplacementGroups({
    afterDragging: getDraggables(last.all, draggables),
    destination: scrolledDroppable,
    displacedBy: impact.displacedBy,
    viewport: viewport.frame,
    last,
    // we want the addition to be animated
    forceShouldAnimate: false
  });
  const invisible = {};
  const visible = {};
  const groups = [
    // this will populate the previous entries with the correct animation values
    last,
    withViewportScroll,
    withDroppableScroll
  ];
  last.all.forEach((id) => {
    const displacement = tryGetVisible(id, groups);
    if (displacement) {
      visible[id] = displacement;
      return;
    }
    invisible[id] = true;
  });

  return {
    ...impact,
    displaced: {
      all: last.all,
      invisible,
      visible
    }
  };
};

export default speculativelyIncrease;
