import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
import _createClass from "@babel/runtime/helpers/createClass";
import _defineProperty from "@babel/runtime/helpers/defineProperty";
import _regeneratorRuntime from "@babel/runtime/regenerator";
import { areUserPreferencesEqual, mergeUserPreferences } from './utils';
/**
 * This class is used to manage user preferences in the editor.
 * It provides methods to load, update, and get user preferences,
 * as well as a way to subscribe to updates.
 * @example const userPreferencesProvider = new UserPreferencesProvider(persistenceAPI, defaultPreferences);
 */
export var UserPreferencesProvider = /*#__PURE__*/function () {
  /**
   * This is the constructor for the UserPreferencesProvider class.
   * @param persistenceAPI - The persistence API to use for loading and updating user preferences
   * @param defaultPreferences - The default user preferences to use
   * @param initialUserPreferences - The initial user preferences to use (optional)
   * @example const userPreferencesProvider = new UserPreferencesProvider(persistenceAPI, defaultPreferences);
   */
  function UserPreferencesProvider(persistenceAPI, defaultPreferences) {
    var _this$persistenceAPI$, _this$persistenceAPI;
    _classCallCheck(this, UserPreferencesProvider);
    _defineProperty(this, "updateCallbacks", []);
    _defineProperty(this, "userPreferences", {});
    _defineProperty(this, "initialized", false);
    this.persistenceAPI = persistenceAPI;
    this.defaultPreferences = defaultPreferences;
    this.resolvedUserPreferences = defaultPreferences;
    var initialUserPreferences = (_this$persistenceAPI$ = (_this$persistenceAPI = this.persistenceAPI).getInitialUserPreferences) === null || _this$persistenceAPI$ === void 0 ? void 0 : _this$persistenceAPI$.call(_this$persistenceAPI);
    if (initialUserPreferences) {
      this.setUserPreferences(initialUserPreferences);
    }
    // the initial user preferences might come from the local cache,
    // so we need to always load the preferences
    this.loadPreferences();
  }

  /**
   * This method returns the initialized state of the user preferences provider
   * @returns true if the user preferences provider is initialized, false otherwise
   * @example userPreferencesProvider.isInitialized
   */
  return _createClass(UserPreferencesProvider, [{
    key: "isInitialized",
    get: function get() {
      return this.initialized;
    }

    /**
     * This method fetches the latest user preferences
     * @returns a promise that resolves with the user preferences, or rejects if error occurs
     * @throws Error if there is an error loading user preferences
     * @example userPreferencesProvider.loadPreferences()
     */
  }, {
    key: "loadPreferences",
    value: (function () {
      var _loadPreferences = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
        var userPreferences;
        return _regeneratorRuntime.wrap(function (_context) {
          while (1) switch (_context.prev = _context.next) {
            case 0:
              _context.next = 1;
              return this.persistenceAPI.loadUserPreferences();
            case 1:
              userPreferences = _context.sent;
              this.setUserPreferences(userPreferences);
            case 2:
            case "end":
              return _context.stop();
          }
        }, _callee, this);
      }));
      function loadPreferences() {
        return _loadPreferences.apply(this, arguments);
      }
      return loadPreferences;
    }()
    /**
     * This method updates a user preference
     * @param key
     * @param value
     * @returns a promise that resolves when the user preference is updated
     * @throws Error if there is an error updating user preferences
     * @example userPreferencesProvider.updatePreference('toolbarDockingPosition', 'top')
     */
    )
  }, {
    key: "updatePreference",
    value: (function () {
      var _updatePreference = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(key, value) {
        var userPreferences;
        return _regeneratorRuntime.wrap(function (_context2) {
          while (1) switch (_context2.prev = _context2.next) {
            case 0:
              _context2.next = 1;
              return this.persistenceAPI.updateUserPreference(key, value);
            case 1:
              userPreferences = _context2.sent;
              this.setUserPreferences(userPreferences);
            case 2:
            case "end":
              return _context2.stop();
          }
        }, _callee2, this);
      }));
      function updatePreference(_x, _x2) {
        return _updatePreference.apply(this, arguments);
      }
      return updatePreference;
    }()
    /**
     * get a user preference, Note that this function is a not async function,
     * meaning that consumers should prefetch the user preference and make it available initially
     * @param key
     * @returns the user preference
     * @example userPreferencesProvider.getPreference('toolbarDockingPosition')
     */
    )
  }, {
    key: "getPreference",
    value: function getPreference(key) {
      return this.resolvedUserPreferences[key];
    }

    /**
     * get all user preferences
     * @returns the user preferences
     * @example userPreferencesProvider.getPreferences()
     */
  }, {
    key: "getPreferences",
    value: function getPreferences() {
      return this.resolvedUserPreferences;
    }

    /**
     * This method fetches the latest user preferences
     * @param onUpdate
     * @returns a function to unsubscribe from the updates
     * @example
     */
  }, {
    key: "onUpdate",
    value: function onUpdate(_onUpdate) {
      var _this = this;
      this.updateCallbacks.push(_onUpdate);

      // Return the cleanup function to unsubscribe from the updates
      return function () {
        _this.updateCallbacks = _this.updateCallbacks.filter(function (callback) {
          return callback !== _onUpdate;
        });
      };
    }

    /**
     * This method is used to set the default user preferences,
     * setting the default user preferences will also trigger an update
     * This is useful when the default user preferences dynamically based on the context
     * @param preferences
     * @example
     */
  }, {
    key: "setDefaultPreferences",
    value: function setDefaultPreferences(preferences) {
      this.defaultPreferences = preferences;
      var hasUpdated = this.resolveUserPreferences();
      if (hasUpdated) {
        this.notifyUserPreferencesUpdated();
      }
    }
  }, {
    key: "setUserPreferences",
    value: function setUserPreferences(userPreferences) {
      this.userPreferences = userPreferences;
      var hasUpdated = this.resolveUserPreferences();
      if (hasUpdated || !this.initialized) {
        if (!this.initialized) {
          this.initialized = true;
        }
        this.notifyUserPreferencesUpdated();
      }
    }

    /**
     * This method is used to notify the user preferences updated
     * @example userPreferencesProvider.notifyUserPreferencesUpdated()
     */
  }, {
    key: "notifyUserPreferencesUpdated",
    value: function notifyUserPreferencesUpdated() {
      var _this2 = this;
      this.updateCallbacks.forEach(function (callback) {
        callback(_this2.resolvedUserPreferences);
      });
    }

    /**
     * This method resolves the user preferences by merging the default preferences
     * with the user preferences and filtering out any undefined or null values
     * to avoid overwriting default preferences with null values
     * @returns true if the user preferences were updated, false otherwise
     * @example userPreferencesProvider.resolveUserPreferences()
     */
  }, {
    key: "resolveUserPreferences",
    value: function resolveUserPreferences() {
      // Merge default preferences with user preferences
      // and filter out any undefined or null values
      // to avoid overwriting default preferences with null values
      var newResolvedUserPreferences = mergeUserPreferences(this.userPreferences, this.defaultPreferences);

      // if the user preferences is NOT initialized, we need to update and notify
      // the user preferences
      // if the user preferences is initialized, we need to check if the new user preferences
      // is different from the old user preferences
      var isSame = areUserPreferencesEqual(newResolvedUserPreferences, this.resolvedUserPreferences);
      var needUpdate = !isSame;
      if (needUpdate) {
        this.resolvedUserPreferences = newResolvedUserPreferences;
      }
      return needUpdate;
    }
  }]);
}();