import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
import _regeneratorRuntime from "@babel/runtime/regenerator";
import { getOnlyFulfilled, waitForAllPromises, waitForFirstFulfilledPromise } from './promise-helpers';
var flatten = function flatten(arr) {
  var _ref;
  return (_ref = []).concat.apply(_ref, _toConsumableArray(arr));
};

/**
 * Allow to run methods from the given provider interface across all providers seamlessly.
 * Handles promise racing and discards rejected promises safely.
 */
export default (function (providers) {
  if (providers.length === 0) {
    throw new Error('At least one provider must be provided');
  }
  var getFulfilledProviders = /*#__PURE__*/function () {
    var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
      var results;
      return _regeneratorRuntime.wrap(function (_context) {
        while (1) switch (_context.prev = _context.next) {
          case 0:
            _context.next = 1;
            return waitForAllPromises(providers.map(function (result) {
              return Promise.resolve(result);
            }));
          case 1:
            results = _context.sent;
            return _context.abrupt("return", getOnlyFulfilled(results).filter(function (provider) {
              return provider != null;
            }));
          case 2:
          case "end":
            return _context.stop();
        }
      }, _callee);
    }));
    return function getFulfilledProviders() {
      return _ref2.apply(this, arguments);
    };
  }();
  var runInAllProviders = /*#__PURE__*/function () {
    var _ref3 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(mapFunction) {
      return _regeneratorRuntime.wrap(function (_context2) {
        while (1) switch (_context2.prev = _context2.next) {
          case 0:
            _context2.next = 1;
            return getFulfilledProviders();
          case 1:
            return _context2.abrupt("return", _context2.sent.map(function (provider) {
              return mapFunction(provider);
            }));
          case 2:
          case "end":
            return _context2.stop();
        }
      }, _callee2);
    }));
    return function runInAllProviders(_x) {
      return _ref3.apply(this, arguments);
    };
  }();

  // Ignored via go/ees005
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  var createCallback = function createCallback(methodName, args) {
    return function (provider) {
      var method = provider[methodName];
      if (typeof method === 'function') {
        return method.apply(provider, args);
      }
      throw new Error("\"".concat(String(methodName), "\" isn't a function of the provider"));
    };
  };

  /**
   * Run a method from the provider which expects to return a single item
   * @param methodName
   * @param args
   */
  // Ignored via go/ees005
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  var invokeSingle = /*#__PURE__*/function () {
    var _ref4 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3(methodName, args) {
      var callback, _t;
      return _regeneratorRuntime.wrap(function (_context3) {
        while (1) switch (_context3.prev = _context3.next) {
          case 0:
            callback = createCallback(methodName, args);
            _t = waitForFirstFulfilledPromise;
            _context3.next = 1;
            return runInAllProviders(callback);
          case 1:
            return _context3.abrupt("return", _t(_context3.sent));
          case 2:
          case "end":
            return _context3.stop();
        }
      }, _callee3);
    }));
    return function invokeSingle(_x2, _x3) {
      return _ref4.apply(this, arguments);
    };
  }();

  /**
   * Run a method in the provider which expectes to return a list of items
   * @param methodName
   * @param args
   */
  // Ignored via go/ees005
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  var invokeList = /*#__PURE__*/function () {
    var _ref5 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee4(methodName, args) {
      var callback, results, fulfilledResults, _t2;
      return _regeneratorRuntime.wrap(function (_context4) {
        while (1) switch (_context4.prev = _context4.next) {
          case 0:
            callback = createCallback(methodName, args);
            _t2 = waitForAllPromises;
            _context4.next = 1;
            return runInAllProviders(callback);
          case 1:
            _context4.next = 2;
            return _t2(_context4.sent);
          case 2:
            results = _context4.sent;
            fulfilledResults = getOnlyFulfilled(results);
            return _context4.abrupt("return", flatten(fulfilledResults).filter(function (result) {
              return result;
            }));
          case 3:
          case "end":
            return _context4.stop();
        }
      }, _callee4);
    }));
    return function invokeList(_x4, _x5) {
      return _ref5.apply(this, arguments);
    };
  }();
  return {
    invokeSingle: invokeSingle,
    invokeList: invokeList
  };
});