import { createLogger } from "../lib/logger/index.js";
import {
  applyApiOverridesToManifests,
  applyModuleOverridesToModules,
  applyPageOverridesToManifests,
  composeApiRouteOverrides,
  composePageRouteOverrides
} from "./overrides.js";
const logger = createLogger("shared").child({ component: "cli-registry" });
function normPath(s) {
  return (s.startsWith("/") ? s : "/" + s).replace(/\/+$/, "") || "/";
}
function segmentSpecificity(seg) {
  if (seg.startsWith("[[...") || seg.startsWith("[...")) return 2;
  if (seg.startsWith("[")) return 1;
  return 0;
}
function compareRouteSpecificity(aPattern, bPattern) {
  const aSegs = aPattern.split("/");
  const bSegs = bPattern.split("/");
  const len = Math.max(aSegs.length, bSegs.length);
  for (let i = 0; i < len; i++) {
    const av = i < aSegs.length ? segmentSpecificity(aSegs[i]) : -1;
    const bv = i < bSegs.length ? segmentSpecificity(bSegs[i]) : -1;
    if (av !== bv) return av - bv;
  }
  return 0;
}
function sortRoutesBySpecificity(routes) {
  return [...routes].sort(
    (a, b) => compareRouteSpecificity(a.pattern ?? a.path ?? "/", b.pattern ?? b.path ?? "/")
  );
}
const sortedRoutesCache = /* @__PURE__ */ new WeakMap();
function ensureSortedRoutes(routes) {
  const cached = sortedRoutesCache.get(routes);
  if (cached) return cached;
  const sorted = sortRoutesBySpecificity([...routes]);
  sortedRoutesCache.set(routes, sorted);
  return sorted;
}
function matchRoutePattern(pattern, pathname) {
  const p = normPath(pattern);
  const u = normPath(pathname);
  const pSegs = p.split("/").slice(1);
  const uSegs = u.split("/").slice(1);
  const params = {};
  let i = 0;
  for (let j = 0; j < pSegs.length; j++, i++) {
    const seg = pSegs[j];
    const mCatchAll = seg.match(/^\[\.\.\.(.+)\]$/);
    const mOptCatch = seg.match(/^\[\[\.\.\.(.+)\]\]$/);
    const mDyn = seg.match(/^\[(.+)\]$/);
    if (mCatchAll) {
      const key = mCatchAll[1];
      if (i >= uSegs.length) return void 0;
      params[key] = uSegs.slice(i);
      return params;
    } else if (mOptCatch) {
      const key = mOptCatch[1];
      params[key] = i < uSegs.length ? uSegs.slice(i) : [];
      return params;
    } else if (mDyn) {
      if (i >= uSegs.length) return void 0;
      params[mDyn[1]] = uSegs[i];
    } else {
      if (i >= uSegs.length || uSegs[i].toLowerCase() !== seg.toLowerCase()) return void 0;
    }
  }
  if (i !== uSegs.length) return void 0;
  return params;
}
function getPattern(r) {
  return r.pattern ?? r.path ?? "/";
}
function findFrontendMatch(modules, pathname) {
  for (const m of modules) {
    const routes = m.frontendRoutes ?? [];
    for (const r of routes) {
      const params = matchRoutePattern(getPattern(r), pathname);
      if (params) return { route: r, params };
    }
  }
}
function findBackendMatch(modules, pathname) {
  for (const m of modules) {
    const routes = m.backendRoutes ?? [];
    for (const r of routes) {
      const params = matchRoutePattern(getPattern(r), pathname);
      if (params) return { route: r, params };
    }
  }
}
function findApi(modules, method, pathname) {
  for (const m of modules) {
    const apis = m.apis ?? [];
    for (const a of apis) {
      if ("handlers" in a) {
        const params = matchRoutePattern(a.path, pathname);
        const handler = a.handlers[method];
        if (params && handler) return { handler, params, requireAuth: a.requireAuth, requireRoles: a.requireRoles, metadata: a.metadata };
      } else {
        const al = a;
        if (al.method !== method) continue;
        const params = matchRoutePattern(al.path, pathname);
        if (params) {
          return { handler: al.handler, params, metadata: al.metadata };
        }
      }
    }
  }
}
function findRouteManifestMatch(routes, pathname) {
  for (const route of ensureSortedRoutes(routes)) {
    const params = matchRoutePattern(route.pattern ?? route.path ?? "/", pathname);
    if (params) {
      return { route, params };
    }
  }
}
function findApiRouteManifestMatch(routes, method, pathname) {
  for (const route of ensureSortedRoutes(routes)) {
    if (!route.methods.includes(method)) continue;
    const params = matchRoutePattern(route.path, pathname);
    if (params) {
      return { route, params };
    }
  }
}
import { resolvePageRouteMetadata } from "./pageRouteMetadata.js";
let _backendRouteManifests = null;
function registerBackendRouteManifests(routes) {
  const pageOverrides = composePageRouteOverrides();
  const finalRoutes = Object.keys(pageOverrides).length === 0 ? routes : applyPageOverridesToManifests(routes, pageOverrides, "backend");
  _backendRouteManifests = sortRoutesBySpecificity(finalRoutes);
}
function getBackendRouteManifests() {
  return _backendRouteManifests ?? [];
}
let _frontendRouteManifests = null;
function registerFrontendRouteManifests(routes) {
  const pageOverrides = composePageRouteOverrides();
  const finalRoutes = Object.keys(pageOverrides).length === 0 ? routes : applyPageOverridesToManifests(routes, pageOverrides, "frontend");
  _frontendRouteManifests = sortRoutesBySpecificity(finalRoutes);
}
function getFrontendRouteManifests() {
  return _frontendRouteManifests ?? [];
}
let _apiRouteManifests = null;
function registerApiRouteManifests(routes) {
  const routeOverrides = composeApiRouteOverrides();
  const finalRoutes = Object.keys(routeOverrides).length === 0 ? routes : applyApiOverridesToManifests(routes, routeOverrides);
  _apiRouteManifests = sortRoutesBySpecificity(finalRoutes);
}
function getApiRouteManifests() {
  return _apiRouteManifests ?? [];
}
let _cliModules = null;
function registerCliModules(modules) {
  if (_cliModules !== null && process.env.NODE_ENV === "development") {
    logger.debug("CLI modules re-registered (this may occur during HMR)");
  }
  _cliModules = applyModuleOverridesToModules(modules);
}
function getCliModules() {
  return _cliModules ?? [];
}
function hasCliModules() {
  return _cliModules !== null && _cliModules.length > 0;
}
function getDefaultEncryptionMaps(modules) {
  const byEntityId = /* @__PURE__ */ new Map();
  for (const mod of modules) {
    for (const entry of mod.defaultEncryptionMaps ?? []) {
      const previous = byEntityId.get(entry.entityId);
      if (previous) {
        throw new Error(
          `[registry] Duplicate default encryption map for "${entry.entityId}" declared by "${previous.moduleId}" and "${mod.id}"`
        );
      }
      byEntityId.set(entry.entityId, {
        moduleId: mod.id,
        map: {
          entityId: entry.entityId,
          ...entry.keyScope ? { keyScope: entry.keyScope } : {},
          fields: entry.fields.map((field) => ({
            field: field.field,
            hashField: field.hashField ?? null
          }))
        }
      });
    }
  }
  return Array.from(byEntityId.values(), ({ map }) => map);
}
function ensureLazyHandler(loaded, kind, id) {
  const handler = typeof loaded === "function" ? loaded : loaded && typeof loaded === "object" && "default" in loaded ? loaded.default : null;
  if (typeof handler !== "function") {
    throw new Error(`[registry] Invalid ${kind} module "${id}" (missing default export handler)`);
  }
  return handler;
}
function createLazyModuleSubscriber(loadModule, id) {
  let handlerPromise = null;
  return async (payload, ctx) => {
    handlerPromise ??= loadModule().then(
      (loaded) => ensureLazyHandler(loaded, "subscriber", id)
    );
    const handler = await handlerPromise;
    return handler(payload, ctx);
  };
}
function createLazyModuleWorker(loadModule, id) {
  let handlerPromise = null;
  return async (job, ctx) => {
    handlerPromise ??= loadModule().then(
      (loaded) => ensureLazyHandler(loaded, "worker", id)
    );
    const handler = await handlerPromise;
    return handler(job, ctx);
  };
}
function createLazyModuleWorkerAbandonHook(loadModule, id) {
  let hookPromise = null;
  return async (payload, info) => {
    hookPromise ??= loadModule().then((loaded) => {
      const metadata = loaded?.metadata;
      return typeof metadata?.onJobAbandoned === "function" ? metadata.onJobAbandoned : null;
    });
    const hook = await hookPromise;
    if (!hook) {
      throw new Error(`[registry] Worker "${id}" was registered with an abandoned-job hook but its metadata no longer declares one`);
    }
    await hook(payload, info);
  };
}
export {
  createLazyModuleSubscriber,
  createLazyModuleWorker,
  createLazyModuleWorkerAbandonHook,
  findApi,
  findApiRouteManifestMatch,
  findBackendMatch,
  findFrontendMatch,
  findRouteManifestMatch,
  getApiRouteManifests,
  getBackendRouteManifests,
  getCliModules,
  getDefaultEncryptionMaps,
  getFrontendRouteManifests,
  hasCliModules,
  matchRoutePattern,
  registerApiRouteManifests,
  registerBackendRouteManifests,
  registerCliModules,
  registerFrontendRouteManifests,
  resolvePageRouteMetadata,
  sortRoutesBySpecificity
};
//# sourceMappingURL=registry.js.map
