/*
  `setInterval` triggers a function every X secs.
  It's not satifying when you deal with asynchronous functions, such as API calls.
  It is indeed possible that the response comes right before the next scheduled call, or even after, defeating the purpose of intervals.
  
  The `interval` function below aims at solving this issue.
  
  Usage: 
  // real life usage, used in a redux thunk
  interval(() => bodymap.get(), {
      // condition for early exit
      exitIf({ status }) { return status && status !== 'pending' },
      // onSuccess handler
      onSuccess(payload) {
        dispatch(bodymapCreationSucceed(payload));
      },
      // onError handler
      onError(error) {
        dispatch(bodymapCreationFailed({
          id: payload.id,
          error,
        }));
      },
      // onTimeout handler, triggered if `exitIf` hasn't been met after`maxIteration` tries
      onTimeout() {
        dispatch(failBodymapCreation({
          id: payload.id,
          error: 'timeout',
        }));
      },
      // number max of iteration - triggers onTimeout handler if maxIteration reached
      maxIteration: 12,
      // time between 2 iterations (in milliseconds)
      time: 5000,
    });
*/

export const interval = (fn, props) => {
  const { exitIf, onSuccess, onError, onTimeout, maxIteration, time } = props;
  let intervalHandler = setTimeout(function () {
    return fn()
    .then(payload => {
      const isExiting = exitIf(payload);
      if (isExiting) {
        return onSuccess(payload);
      }
      if (maxIteration > 1) {
        intervalHandler = interval(fn, { ...props, maxIteration: maxIteration - 1 });
        return intervalHandler;
      }
      return onTimeout();
    })
    .catch(error => onError(error));
  }, time);

  return intervalHandler;
};