import { isNonNullable, isNullable } from "../utils";
var CALLBACK_AS_KEY = {
  callbackAsKey: true
};
var cache = new WeakMap();

/**
 * Позволяет объединить несколько параметров ref в один вызов, в котором во все переданные параметры просетится ref.
 *
 * Кеширует результат возвращаемой функции, так что при одинаковых входных параметрах React-у будет возвращена одинаковая функция.
 * Это позволит не вызывать лишние commitAttachRef и commitDetachRef и не ловить сайдэффекты связанные со значением ref в моменте
 *
 * Не прокидывай в параметрах стрелочные функции, так результат не будет закеширован.
 *
 * @returns function that passed refs: (...refs) =>
 *
 * @example
 * const SomeComponent = forwardRef((props, ref) => {
 *  const localRef = useRef();
 *  return <div ref={mergeRefs(localRef, ref)} />;
 * });
 */
export function mergeRefs() {
  for (var _len = arguments.length, refs = new Array(_len), _key = 0; _key < _len; _key++) {
    refs[_key] = arguments[_key];
  }
  var cacheLevel = getLeafRefInCache.apply(void 0, refs);
  var cachedCallback = cacheLevel.get(CALLBACK_AS_KEY);
  if (cachedCallback && typeof cachedCallback === 'function') {
    return cachedCallback;
  }
  var newRefCallback = createRefCallback(refs);
  cacheLevel.set(CALLBACK_AS_KEY, newRefCallback);
  return newRefCallback;
}
function createRefCallback(refs) {
  function applyRef(value) {
    refs.forEach(function (ref) {
      if (typeof ref === 'function') {
        return ref(value);
      } else if (isNonNullable(ref)) {
        return ref.current = value;
      }
    });
  }
  return applyRef;
}
function getLeafRefInCache() {
  var cacheLevel = cache;
  for (var _len2 = arguments.length, refs = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
    refs[_key2] = arguments[_key2];
  }
  for (var _i = 0, _refs = refs; _i < _refs.length; _i++) {
    var ref = _refs[_i];
    if (isNullable(ref)) {
      continue;
    }
    var child = cacheLevel.get(ref);
    if (child && typeof child !== 'function') {
      cacheLevel = child;
    } else {
      var leaf = new WeakMap();
      cacheLevel.set(ref, leaf);
      cacheLevel = leaf;
    }
  }
  return cacheLevel;
}