import { defer } from './smartpromise.classes.deferred.js';

export * from './smartpromise.classes.cumulativedeferred.js';
export * from './smartpromise.classes.deferred.js';


/**
 * Creates a new resolved promise for the provided value.
 */
export const resolvedPromise = <T>(value?: T): Promise<T> => {
  return Promise.resolve(value);
};

/**
 * Creates a new rejected promise for the provided reason.
 */
export const rejectedPromise = (err) => {
  return Promise.reject(err);
};

interface IAsyncFunction<T> {
  (someArg: T): Promise<T>;
}

/**
 * accepts an array of inputs and a function that accepts the input.
 * runs all items with the function and returns the result array when all items have run
 * @param inputArg
 * @param functionArg
 */
export const map = async <T>(inputArg: T[], functionArg: IAsyncFunction<T>) => {
  const promiseArray: Promise<any>[] = [];
  const resultArray = [];
  for (const item of inputArg) {
    const promise: Promise<any> = functionArg(item);
    promiseArray.push(promise);
    promise.then((x) => {
      resultArray.push(x);
    });
  }
  await Promise.all(promiseArray);
  return resultArray;
};

export const timeoutWrap = async <T = any>(
  promiseArg: Promise<T>,
  timeoutInMsArg: number,
  rejectArg = true
) => {
  return new Promise<T>((resolve, reject) => {
    setTimeout(() => {
      if (rejectArg) {
        reject(new Error('timeout'));
      } else {
        resolve(null);
      }
    }, timeoutInMsArg);
    promiseArg.then(resolve, reject);
  });
};

export const timeoutAndContinue = async <T = any>(
  promiseArg: Promise<T>,
  timeoutInMsArg = 60000
) => {
  return timeoutWrap(promiseArg, timeoutInMsArg, false);
};

export const getFirstTrueOrFalse = async (promisesArg: Promise<boolean>[]) => {
  const done = defer<boolean>();
  for (const promiseArg of promisesArg) {
    promiseArg.then((resultArg) => {
      if (resultArg === true) {
        done.resolve(true);
      }
    });
  }
  Promise.all(promisesArg).then(() => {
    done.resolve(false);
  });
  return done.promise;
};
