import { Data } from '../../../../types';
import { DynamicListReducerState } from './DynamicListReducer.types';

export const addItem = <T extends Data>(
  item: T,
  items: DynamicListReducerState<T>['items'],
  positionPropertyName: DynamicListReducerState<T>['positionPropertyName'],
): T[] => {
  let newValue: T[] = [];
  if (positionPropertyName) {
    // We can safely push this item anywhere in the array as long as the reducer re-arranges the entire array based on positions
    newValue.push(item);

    items.forEach((value) => {
      if (value[positionPropertyName] < item[positionPropertyName]) {
        // Items before the new item
        return newValue.push(value);
      } else if (value[positionPropertyName] === item[positionPropertyName]) {
        // If an item already exists in the same position, we need to increment the position of the existing item
        newValue.push({
          ...value,
          [positionPropertyName]: value[positionPropertyName] + 1,
        });
      } else if (value[positionPropertyName] > item[positionPropertyName]) {
        // Increment the rest of the items
        if (newValue[newValue.length - 1].position === value.position) {
          newValue.push({
            ...value,
            [positionPropertyName]: value[positionPropertyName] + 1,
          });
        } else {
          return newValue.push(value);
        }
      }
    });
  } else {
    newValue = [...items, item];
  }

  return newValue;
};

export const removeItem = <T extends Data>(
  item: T,
  items: DynamicListReducerState<T>['items'],
  positionPropertyName: DynamicListReducerState<T>['positionPropertyName'],
): T[] => {
  let newValue: T[] = [];
  if (positionPropertyName) {
    let hasReachedGap = false;

    items.forEach((value) => {
      if (value[positionPropertyName] < item[positionPropertyName]) {
        // Items before the removed item
        return newValue.push(value);
      } else if (value[positionPropertyName] > item[positionPropertyName]) {
        // Check if a gap was reached
        hasReachedGap =
          hasReachedGap || isGap(items[items.indexOf(value) - 1], value);

        // Items after the removed item
        if (!hasReachedGap) {
          return newValue.push({
            ...value,
            [positionPropertyName]: value[positionPropertyName] - 1,
          });
        } else {
          return newValue.push(value);
        }
      }
    });
  } else {
    newValue = items.filter((x) => x !== item);
  }

  return newValue;
};

const isGap = <T extends Data>(previousItem: T, nextItem: T): boolean => {
  const previousPosition = previousItem?.position;
  const nextPosition = nextItem?.position;

  return (
    previousPosition && nextPosition && previousPosition + 1 < nextPosition
  );
};
