import { createLogger } from "../logger/index.js";
const logger = createLogger("shared").child({ component: "commands" });
class CommandRegistry {
  constructor() {
    this.handlers = /* @__PURE__ */ new Map();
    this.loadersById = /* @__PURE__ */ new Map();
    this.fallbackLoadersByModule = /* @__PURE__ */ new Map();
    this.loadedLoaderKeys = /* @__PURE__ */ new Set();
    this.loadingLoaderKeys = /* @__PURE__ */ new Map();
    this.didWarnAboutDevelopmentReregistration = false;
    this.didWarnAboutDevelopmentLoaderReregistration = false;
  }
  register(handler) {
    if (!handler?.id) throw new Error("Command handler must define an id");
    if (this.handlers.has(handler.id)) {
      if (process.env.NODE_ENV === "development") {
        if (!this.didWarnAboutDevelopmentReregistration) {
          logger.debug("Commands re-registered (this may occur during HMR)");
          this.didWarnAboutDevelopmentReregistration = true;
        }
        this.handlers.set(handler.id, handler);
        return;
      }
      throw new Error(`Duplicate command registration for id ${handler.id}`);
    }
    this.handlers.set(handler.id, handler);
  }
  registerLoaders(loaders) {
    for (const loader of loaders) {
      if (!loader?.moduleId) throw new Error("Command loader must define a moduleId");
      if (typeof loader.load !== "function") throw new Error("Command loader must define a load function");
      if (loader.id) {
        if (this.loadersById.has(loader.id) && process.env.NODE_ENV !== "development") {
          throw new Error(`Duplicate command loader registration for id ${loader.id}`);
        }
        if (this.loadersById.has(loader.id) && process.env.NODE_ENV === "development" && !this.didWarnAboutDevelopmentLoaderReregistration) {
          logger.debug("Command loaders re-registered (this may occur during HMR)");
          this.didWarnAboutDevelopmentLoaderReregistration = true;
        }
        this.loadersById.set(loader.id, loader);
        continue;
      }
      const key = loader.key ?? `${loader.moduleId}:fallback:${this.fallbackLoadersByModule.get(loader.moduleId)?.size ?? 0}`;
      const existing = this.fallbackLoadersByModule.get(loader.moduleId) ?? /* @__PURE__ */ new Map();
      if (existing.has(key) && process.env.NODE_ENV !== "development") {
        throw new Error(`Duplicate command loader registration for key ${key}`);
      }
      if (existing.has(key) && process.env.NODE_ENV === "development" && !this.didWarnAboutDevelopmentLoaderReregistration) {
        logger.debug("Command loaders re-registered (this may occur during HMR)");
        this.didWarnAboutDevelopmentLoaderReregistration = true;
      }
      existing.set(key, loader);
      this.fallbackLoadersByModule.set(loader.moduleId, existing);
    }
  }
  unregister(id) {
    this.handlers.delete(id);
  }
  get(id) {
    return this.handlers.get(id) ?? null;
  }
  has(id) {
    return this.handlers.has(id) || this.loadersById.has(id);
  }
  /**
   * List all known command IDs, including exact lazy loaders that have not
   * been imported yet.
   */
  list() {
    return Array.from(/* @__PURE__ */ new Set([...this.handlers.keys(), ...this.loadersById.keys()]));
  }
  async load(commandId) {
    const existing = this.get(commandId);
    if (existing) return existing;
    const moduleId = commandId.split(".")[0];
    const exact = this.loadersById.get(commandId);
    if (exact) {
      await this.loadOnce(exact.key ?? commandId, exact);
      const loaded = this.get(commandId);
      if (loaded) {
        await this.loadModuleFallbacks(moduleId);
        return loaded;
      }
    }
    await this.loadModuleFallbacks(moduleId);
    return this.get(commandId);
  }
  listLoaders() {
    return [
      ...Array.from(this.loadersById.keys()),
      ...Array.from(this.fallbackLoadersByModule.values()).flatMap((loaders) => Array.from(loaders.keys()))
    ];
  }
  clear() {
    this.handlers.clear();
    this.loadersById.clear();
    this.fallbackLoadersByModule.clear();
    this.loadedLoaderKeys.clear();
    this.loadingLoaderKeys.clear();
    this.didWarnAboutDevelopmentReregistration = false;
    this.didWarnAboutDevelopmentLoaderReregistration = false;
  }
  async loadOnce(key, loader) {
    if (this.loadedLoaderKeys.has(key)) return;
    const pending = this.loadingLoaderKeys.get(key);
    if (pending) return pending;
    const promise = Promise.resolve().then(() => loader.load()).then(() => {
      this.loadedLoaderKeys.add(key);
    }).finally(() => {
      this.loadingLoaderKeys.delete(key);
    });
    this.loadingLoaderKeys.set(key, promise);
    return promise;
  }
  async loadModuleFallbacks(moduleId) {
    const fallbacks = Array.from(this.fallbackLoadersByModule.get(moduleId)?.entries() ?? []);
    for (const [key, loader] of fallbacks) {
      await this.loadOnce(key, loader);
    }
  }
}
const commandRegistry = new CommandRegistry();
function registerCommand(handler) {
  commandRegistry.register(handler);
}
function unregisterCommand(id) {
  commandRegistry.unregister(id);
}
function registerCommandLoaders(loaders) {
  commandRegistry.registerLoaders(loaders);
}
export {
  commandRegistry,
  registerCommand,
  registerCommandLoaders,
  unregisterCommand
};
//# sourceMappingURL=registry.js.map
