import { createLogger } from "../../lib/logger/index.js";
const logger = createLogger("events").child({ component: "factory" });
const GLOBAL_EVENT_BUS_KEY = "__openMercatoGlobalEventBus__";
let globalEventBus = null;
function setGlobalEventBus(bus) {
  globalEventBus = bus;
  try {
    ;
    globalThis[GLOBAL_EVENT_BUS_KEY] = bus;
  } catch {
  }
}
function getGlobalEventBus() {
  try {
    const sharedBus = globalThis[GLOBAL_EVENT_BUS_KEY];
    if (sharedBus && typeof sharedBus === "object" && typeof sharedBus.emit === "function") {
      return sharedBus;
    }
  } catch {
  }
  return globalEventBus;
}
const GLOBAL_EVENT_REGISTRY_KEY = "__openMercatoEventDefinitionRegistry__";
const fallbackEventRegistryState = {
  declaredEventIds: /* @__PURE__ */ new Set(),
  declaredEvents: [],
  registeredEventConfigs: null
};
function isEventRegistryState(value) {
  if (!value || typeof value !== "object") return false;
  const candidate = value;
  return candidate.declaredEventIds instanceof Set && Array.isArray(candidate.declaredEvents) && (candidate.registeredEventConfigs === null || Array.isArray(candidate.registeredEventConfigs));
}
function getEventRegistryState() {
  try {
    const globalScope = globalThis;
    const existing = globalScope[GLOBAL_EVENT_REGISTRY_KEY];
    if (isEventRegistryState(existing)) return existing;
    globalScope[GLOBAL_EVENT_REGISTRY_KEY] = fallbackEventRegistryState;
    return fallbackEventRegistryState;
  } catch {
    return fallbackEventRegistryState;
  }
}
function addDeclaredEvent(event) {
  const state = getEventRegistryState();
  state.declaredEventIds.add(event.id);
  const existingIndex = state.declaredEvents.findIndex((candidate) => candidate.id === event.id);
  if (existingIndex < 0) {
    state.declaredEvents.push(event);
    return;
  }
  if (state.declaredEvents[existingIndex]?.module === event.module) {
    state.declaredEvents[existingIndex] = event;
  }
}
function isEventDeclared(eventId) {
  return getEventRegistryState().declaredEventIds.has(eventId);
}
function getAllDeclaredEventIds() {
  return Array.from(getEventRegistryState().declaredEventIds);
}
function getDeclaredEvents() {
  return [...getEventRegistryState().declaredEvents];
}
function isBroadcastEvent(eventId) {
  const event = getEventRegistryState().declaredEvents.find((e) => e.id === eventId);
  return event?.clientBroadcast === true;
}
function isCrossProcessBroadcastEvent(eventId) {
  const event = getEventRegistryState().declaredEvents.find((e) => e.id === eventId);
  return event?.clientBroadcast === true || event?.crossProcessBroadcast === true;
}
function isPrivateCrossProcessBroadcastEvent(eventId) {
  const event = getEventRegistryState().declaredEvents.find((e) => e.id === eventId);
  return event?.crossProcessBroadcast === true && event?.clientBroadcast !== true;
}
function isPrivateCrossProcessEventEmitter(eventId, emitterModuleId) {
  const event = getEventRegistryState().declaredEvents.find((e) => e.id === eventId);
  if (event?.crossProcessBroadcast !== true) return true;
  return typeof event.module === "string" && event.module.length > 0 && event.module === emitterModuleId;
}
function isPortalBroadcastEvent(eventId) {
  const event = getEventRegistryState().declaredEvents.find((e) => e.id === eventId);
  return event?.portalBroadcast === true;
}
function registerEventModuleConfigs(configs) {
  const state = getEventRegistryState();
  if (state.registeredEventConfigs !== null && process.env.NODE_ENV === "development") {
    logger.debug("Event module configs re-registered (this may occur during HMR)");
  }
  state.registeredEventConfigs = configs;
  for (const config of configs) {
    for (const event of config.events) {
      addDeclaredEvent(event);
    }
  }
}
function getEventModuleConfigs() {
  return getEventRegistryState().registeredEventConfigs ?? [];
}
function createModuleEvents(options) {
  const { moduleId, events, strict = false } = options;
  const validEventIds = new Set(events.map((e) => e.id));
  const fullEvents = events.map((e) => ({
    ...e,
    module: moduleId
  }));
  for (const event of fullEvents) {
    addDeclaredEvent(event);
  }
  const emit = async (eventId, payload, emitOptions) => {
    if (!validEventIds.has(eventId)) {
      const message = `[events] Module "${moduleId}" tried to emit undeclared event "${eventId}". Add it to the module's events.ts file first.`;
      if (strict) {
        throw new Error(message);
      } else {
        logger.error("Module tried to emit undeclared event \u2014 add it to the module events.ts first", { moduleId, eventId });
      }
    }
    const eventBus = getGlobalEventBus();
    if (!eventBus) {
      logger.warn("Event bus not available, cannot emit event", { eventId });
      return;
    }
    const eventDefinition = fullEvents.find((event) => event.id === eventId);
    const isClientBroadcast = eventDefinition?.clientBroadcast === true;
    const trustedOptions = eventDefinition?.crossProcessBroadcast === true || isClientBroadcast ? {
      ...emitOptions,
      // Browser-broadcast module emitters historically accepted scope in
      // their typed payload. Preserve that contract at the trusted module
      // boundary while the event bus itself relies only on options.
      ...isClientBroadcast && emitOptions?.tenantId === void 0 ? { tenantId: payload.tenantId ?? null } : {},
      ...isClientBroadcast && emitOptions?.organizationId === void 0 ? { organizationId: payload.organizationId ?? null } : {},
      ...isClientBroadcast && emitOptions?.organizationIds === void 0 && Array.isArray(payload.organizationIds) ? { organizationIds: payload.organizationIds.filter((value) => typeof value === "string") } : {},
      emitterModuleId: moduleId
    } : emitOptions;
    await eventBus.emit(eventId, payload, trustedOptions);
  };
  return {
    moduleId,
    events: fullEvents,
    emit
  };
}
export {
  createModuleEvents,
  getAllDeclaredEventIds,
  getDeclaredEvents,
  getEventModuleConfigs,
  getGlobalEventBus,
  isBroadcastEvent,
  isCrossProcessBroadcastEvent,
  isEventDeclared,
  isPortalBroadcastEvent,
  isPrivateCrossProcessBroadcastEvent,
  isPrivateCrossProcessEventEmitter,
  registerEventModuleConfigs,
  setGlobalEventBus
};
//# sourceMappingURL=factory.js.map
