import { PauseableEmitter, Emitter } from "../../../base/common/event.mjs";
import { Disposable } from "../../../base/common/lifecycle.mjs";
import { isUndefinedOrNull } from "../../../base/common/types.mjs";
import { Storage, InMemoryStorageDatabase } from "../../../base/parts/storage/common/storage.mjs";
import { createDecorator } from "../../instantiation/common/instantiation.mjs";
const TARGET_KEY = "__$__targetStorageMarker";
const IStorageService = createDecorator("storageService");
var WillSaveStateReason;
(function(WillSaveStateReason2) {
  WillSaveStateReason2[WillSaveStateReason2["NONE"] = 0] = "NONE";
  WillSaveStateReason2[WillSaveStateReason2["SHUTDOWN"] = 1] = "SHUTDOWN";
})(WillSaveStateReason || (WillSaveStateReason = {}));
class AbstractStorageService extends Disposable {
  constructor(options = { flushInterval: AbstractStorageService.DEFAULT_FLUSH_INTERVAL }) {
    super();
    this.options = options;
    this._onDidChangeValue = this._register(new PauseableEmitter());
    this._onDidChangeTarget = this._register(new PauseableEmitter());
    this._onWillSaveState = this._register(new Emitter());
    this.onWillSaveState = this._onWillSaveState.event;
    this._workspaceKeyTargets = void 0;
    this._globalKeyTargets = void 0;
  }
  emitDidChangeValue(scope, key) {
    if (key === TARGET_KEY) {
      if (scope === 0) {
        this._globalKeyTargets = void 0;
      } else if (scope === 1) {
        this._workspaceKeyTargets = void 0;
      }
      this._onDidChangeTarget.fire({ scope });
    } else {
      this._onDidChangeValue.fire({ scope, key, target: this.getKeyTargets(scope)[key] });
    }
  }
  get(key, scope, fallbackValue) {
    var _a;
    return (_a = this.getStorage(scope)) === null || _a === void 0 ? void 0 : _a.get(key, fallbackValue);
  }
  getBoolean(key, scope, fallbackValue) {
    var _a;
    return (_a = this.getStorage(scope)) === null || _a === void 0 ? void 0 : _a.getBoolean(key, fallbackValue);
  }
  getNumber(key, scope, fallbackValue) {
    var _a;
    return (_a = this.getStorage(scope)) === null || _a === void 0 ? void 0 : _a.getNumber(key, fallbackValue);
  }
  store(key, value, scope, target) {
    if (isUndefinedOrNull(value)) {
      this.remove(key, scope);
      return;
    }
    this.withPausedEmitters(() => {
      var _a;
      this.updateKeyTarget(key, scope, target);
      (_a = this.getStorage(scope)) === null || _a === void 0 ? void 0 : _a.set(key, value);
    });
  }
  remove(key, scope) {
    this.withPausedEmitters(() => {
      var _a;
      this.updateKeyTarget(key, scope, void 0);
      (_a = this.getStorage(scope)) === null || _a === void 0 ? void 0 : _a.delete(key);
    });
  }
  withPausedEmitters(fn) {
    this._onDidChangeValue.pause();
    this._onDidChangeTarget.pause();
    try {
      fn();
    } finally {
      this._onDidChangeValue.resume();
      this._onDidChangeTarget.resume();
    }
  }
  updateKeyTarget(key, scope, target) {
    var _a, _b;
    const keyTargets = this.getKeyTargets(scope);
    if (typeof target === "number") {
      if (keyTargets[key] !== target) {
        keyTargets[key] = target;
        (_a = this.getStorage(scope)) === null || _a === void 0 ? void 0 : _a.set(TARGET_KEY, JSON.stringify(keyTargets));
      }
    } else {
      if (typeof keyTargets[key] === "number") {
        delete keyTargets[key];
        (_b = this.getStorage(scope)) === null || _b === void 0 ? void 0 : _b.set(TARGET_KEY, JSON.stringify(keyTargets));
      }
    }
  }
  get workspaceKeyTargets() {
    if (!this._workspaceKeyTargets) {
      this._workspaceKeyTargets = this.loadKeyTargets(
        1
        /* WORKSPACE */
      );
    }
    return this._workspaceKeyTargets;
  }
  get globalKeyTargets() {
    if (!this._globalKeyTargets) {
      this._globalKeyTargets = this.loadKeyTargets(
        0
        /* GLOBAL */
      );
    }
    return this._globalKeyTargets;
  }
  getKeyTargets(scope) {
    return scope === 0 ? this.globalKeyTargets : this.workspaceKeyTargets;
  }
  loadKeyTargets(scope) {
    const keysRaw = this.get(TARGET_KEY, scope);
    if (keysRaw) {
      try {
        return JSON.parse(keysRaw);
      } catch (error) {
      }
    }
    return /* @__PURE__ */ Object.create(null);
  }
}
AbstractStorageService.DEFAULT_FLUSH_INTERVAL = 60 * 1e3;
class InMemoryStorageService extends AbstractStorageService {
  constructor() {
    super();
    this.globalStorage = this._register(new Storage(new InMemoryStorageDatabase()));
    this.workspaceStorage = this._register(new Storage(new InMemoryStorageDatabase()));
    this._register(this.workspaceStorage.onDidChangeStorage((key) => this.emitDidChangeValue(1, key)));
    this._register(this.globalStorage.onDidChangeStorage((key) => this.emitDidChangeValue(0, key)));
  }
  getStorage(scope) {
    return scope === 0 ? this.globalStorage : this.workspaceStorage;
  }
}
export {
  AbstractStorageService,
  IStorageService,
  InMemoryStorageService,
  WillSaveStateReason
};
