/**
 * @param {*[]} array
 * @param {number} batchSize
 * @returns {*[]}
 */
function chunk(array, batchSize = 4) {
  const chunked = [];
  for (let i = 0; i < array.length; i += batchSize) {
    chunked.push(array.slice(i, i + batchSize));
  }

  return chunked;
}

/**
 * @param {*[]} dataArray
 * @param {Function} mapper
 * @param {{batchSize: number, delayMs: number}} options
 * @returns {Promise<*[]>}
 */
function promiseChunks(dataArray, mapper, { batchSize, delayMs = 1000 } = {}) {
  if (!Array.isArray(dataArray)) return [];

  const chunkedData = chunk(dataArray, batchSize);

  return chunkedData.reduce(
    (chain, batch) =>
      chain
        .then((accumulatedData) =>
          Promise.all(batch.map(mapper)).then((newData) =>
            accumulatedData && typeof accumulatedData.length !== 'undefined'
              ? [...accumulatedData, ...newData]
              : newData,
          ),
        )
        // Adds timeout between request chunks
        .then(
          (data) =>
            new Promise((resolve) => {
              setTimeout(resolve, dataArray.length > batchSize ? delayMs : 0, data);
            }),
        ),
    Promise.resolve(),
  );
}

module.exports = promiseChunks;
