'use strict';

var sort_cjs = {};

var hasRequiredSort_cjs;
function requireSort_cjs() {
  if (hasRequiredSort_cjs) return sort_cjs;
  hasRequiredSort_cjs = 1;
  Object.defineProperty(sort_cjs, '__esModule', {
    value: true
  });

  // >>> INTERFACES <<<
  // >>> HELPERS <<<
  var castComparer = function (comparer) {
    return function (a, b, order) {
      return comparer(a, b, order) * order;
    };
  };
  var throwInvalidConfigErrorIfTrue = function (condition, context) {
    if (condition) throw Error("Invalid sort config: " + context);
  };
  var unpackObjectSorter = function (sortByObj) {
    var _a = sortByObj || {},
      asc = _a.asc,
      desc = _a.desc;
    var order = asc ? 1 : -1;
    var sortBy = asc || desc;
    // Validate object config
    throwInvalidConfigErrorIfTrue(!sortBy, 'Expected `asc` or `desc` property');
    throwInvalidConfigErrorIfTrue(asc && desc, 'Ambiguous object with `asc` and `desc` config properties');
    var comparer = sortByObj.comparer && castComparer(sortByObj.comparer);
    return {
      order: order,
      sortBy: sortBy,
      comparer: comparer
    };
  };
  // >>> SORTERS <<<
  var multiPropertySorterProvider = function (defaultComparer) {
    return function multiPropertySorter(sortBy, sortByArr, depth, order, comparer, a, b) {
      var valA;
      var valB;
      if (typeof sortBy === 'string') {
        valA = a[sortBy];
        valB = b[sortBy];
      } else if (typeof sortBy === 'function') {
        valA = sortBy(a);
        valB = sortBy(b);
      } else {
        var objectSorterConfig = unpackObjectSorter(sortBy);
        return multiPropertySorter(objectSorterConfig.sortBy, sortByArr, depth, objectSorterConfig.order, objectSorterConfig.comparer || defaultComparer, a, b);
      }
      var equality = comparer(valA, valB, order);
      if ((equality === 0 || valA == null && valB == null) && sortByArr.length > depth) {
        return multiPropertySorter(sortByArr[depth], sortByArr, depth + 1, order, comparer, a, b);
      }
      return equality;
    };
  };
  function getSortStrategy(sortBy, comparer, order) {
    // Flat array sorter
    if (sortBy === undefined || sortBy === true) {
      return function (a, b) {
        return comparer(a, b, order);
      };
    }
    // Sort list of objects by single object key
    if (typeof sortBy === 'string') {
      throwInvalidConfigErrorIfTrue(sortBy.includes('.'), 'String syntax not allowed for nested properties.');
      return function (a, b) {
        return comparer(a[sortBy], b[sortBy], order);
      };
    }
    // Sort list of objects by single function sorter
    if (typeof sortBy === 'function') {
      return function (a, b) {
        return comparer(sortBy(a), sortBy(b), order);
      };
    }
    // Sort by multiple properties
    if (Array.isArray(sortBy)) {
      var multiPropSorter_1 = multiPropertySorterProvider(comparer);
      return function (a, b) {
        return multiPropSorter_1(sortBy[0], sortBy, 1, order, comparer, a, b);
      };
    }
    // Unpack object config to get actual sorter strategy
    var objectSorterConfig = unpackObjectSorter(sortBy);
    return getSortStrategy(objectSorterConfig.sortBy, objectSorterConfig.comparer || comparer, objectSorterConfig.order);
  }
  var sortArray = function (order, ctx, sortBy, comparer) {
    var _a;
    if (!Array.isArray(ctx)) {
      return ctx;
    }
    // Unwrap sortBy if array with only 1 value to get faster sort strategy
    if (Array.isArray(sortBy) && sortBy.length < 2) {
      _a = sortBy, sortBy = _a[0];
    }
    return ctx.sort(getSortStrategy(sortBy, comparer, order));
  };
  function createNewSortInstance(opts) {
    var comparer = castComparer(opts.comparer);
    return function (arrayToSort) {
      var ctx = Array.isArray(arrayToSort) && !opts.inPlaceSorting ? arrayToSort.slice() : arrayToSort;
      return {
        asc: function (sortBy) {
          return sortArray(1, ctx, sortBy, comparer);
        },
        desc: function (sortBy) {
          return sortArray(-1, ctx, sortBy, comparer);
        },
        by: function (sortBy) {
          return sortArray(1, ctx, sortBy, comparer);
        }
      };
    };
  }
  var defaultComparer = function (a, b, order) {
    if (a == null) return order;
    if (b == null) return -order;
    if (typeof a !== typeof b) {
      return typeof a < typeof b ? -1 : 1;
    }
    if (a < b) return -1;
    if (a > b) return 1;
    return 0;
  };
  var sort = createNewSortInstance({
    comparer: defaultComparer
  });
  var inPlaceSort = createNewSortInstance({
    comparer: defaultComparer,
    inPlaceSorting: true
  });
  sort_cjs.createNewSortInstance = createNewSortInstance;
  sort_cjs.defaultComparer = defaultComparer;
  sort_cjs.inPlaceSort = inPlaceSort;
  sort_cjs.sort = sort;
  return sort_cjs;
}

var fastSort;
var hasRequiredFastSort;
function requireFastSort() {
  if (hasRequiredFastSort) return fastSort;
  hasRequiredFastSort = 1;
  fastSort = requireSort_cjs();
  return fastSort;
}

var fastSortExports = requireFastSort();

module.exports = fastSortExports;
