import _typeof from "@babel/runtime/helpers/esm/typeof";
import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck";
import _createClass from "@babel/runtime/helpers/esm/createClass";
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
import React from 'react';
var BEAT_LIMIT = 1000 * 60 * 10;

/**
 * A helper class to map keys to values.
 * It supports both primitive keys and object keys.
 */
var ArrayKeyMap = /*#__PURE__*/function () {
  function ArrayKeyMap() {
    _classCallCheck(this, ArrayKeyMap);
    _defineProperty(this, "map", new Map());
    // Use WeakMap to avoid memory leak
    _defineProperty(this, "objectIDMap", new WeakMap());
    _defineProperty(this, "nextID", 0);
    _defineProperty(this, "lastAccessBeat", new Map());
    // We will clean up the cache when reach the limit
    _defineProperty(this, "accessBeat", 0);
  }
  _createClass(ArrayKeyMap, [{
    key: "set",
    value: function set(keys, value) {
      // New set will trigger clear
      this.clear();

      // Set logic
      var compositeKey = this.getCompositeKey(keys);
      this.map.set(compositeKey, value);
      this.lastAccessBeat.set(compositeKey, Date.now());
    }
  }, {
    key: "get",
    value: function get(keys) {
      var compositeKey = this.getCompositeKey(keys);
      var cache = this.map.get(compositeKey);
      this.lastAccessBeat.set(compositeKey, Date.now());
      this.accessBeat += 1;
      return cache;
    }
  }, {
    key: "getCompositeKey",
    value: function getCompositeKey(keys) {
      var _this = this;
      var ids = keys.map(function (key) {
        if (key && _typeof(key) === 'object') {
          return "obj_".concat(_this.getObjectID(key));
        }
        return "".concat(_typeof(key), "_").concat(key);
      });
      return ids.join('|');
    }
  }, {
    key: "getObjectID",
    value: function getObjectID(obj) {
      if (this.objectIDMap.has(obj)) {
        return this.objectIDMap.get(obj);
      }
      var id = this.nextID;
      this.objectIDMap.set(obj, id);
      this.nextID += 1;
      return id;
    }
  }, {
    key: "clear",
    value: function clear() {
      var _this2 = this;
      if (this.accessBeat > 10000) {
        var now = Date.now();
        this.lastAccessBeat.forEach(function (beat, key) {
          if (now - beat > BEAT_LIMIT) {
            _this2.map.delete(key);
            _this2.lastAccessBeat.delete(key);
          }
        });
        this.accessBeat = 0;
      }
    }
  }]);
  return ArrayKeyMap;
}();
var uniqueMap = new ArrayKeyMap();

/**
 * Like `useMemo`, but this hook result will be shared across all instances.
 */
function useUniqueMemo(memoFn, deps) {
  return React.useMemo(function () {
    var cachedValue = uniqueMap.get(deps);
    if (cachedValue) {
      return cachedValue;
    }
    var newValue = memoFn();
    uniqueMap.set(deps, newValue);
    return newValue;
  }, deps);
}
export default useUniqueMemo;