/**
 * Client-safe route map builder
 *
 * Provides a fluent API for building route maps with prefixes.
 * Can be imported in client code without pulling in server dependencies.
 *
 * @example
 * ```typescript
 * import { createRouteMap, registerRouteMap } from "rsc-router/browser";
 *
 * const routeMap = createRouteMap()
 *   .add(homeRoutes)
 *   .add(blogRoutes, "blog")
 *   .add(shopRoutes, "shop");
 *
 * registerRouteMap(routeMap.routes);
 *
 * declare global {
 *   namespace RSCRouter {
 *     interface RegisteredRoutes extends typeof routeMap.routes {}
 *   }
 * }
 * ```
 */
/**
 * Add routes to a map with optional prefix
 * Keys stay unchanged for composability - only URL patterns get prefixed.
 *
 * @param routeMap - The map to add routes to
 * @param routes - Routes to add
 * @param prefix - Optional prefix for URL paths WITHOUT leading slash (keys stay unchanged)
 */
function addRoutes(routeMap, routes, prefix = "") {
    // Normalize prefix: remove leading slash if accidentally provided
    const normalizedPrefix = prefix.startsWith("/") ? prefix.slice(1) : prefix;
    for (const [key, pattern] of Object.entries(routes)) {
        const prefixedPattern = normalizedPrefix && pattern !== "/"
            ? `/${normalizedPrefix}${pattern}`
            : normalizedPrefix && pattern === "/"
                ? `/${normalizedPrefix}`
                : pattern;
        // Use original key - enables reusable route modules
        routeMap[key] = prefixedPattern;
    }
}
/**
 * Create a new route map builder
 *
 * @returns A builder for accumulating routes with type-safe prefixes
 *
 * @example
 * ```typescript
 * const routeMap = createRouteMap()
 *   .add(homeRoutes)
 *   .add(blogRoutes, "blog");
 *
 * // Types are accumulated through the chain
 * type AppRoutes = typeof routeMap.routes;
 * ```
 */
export function createRouteMap() {
    const routeMap = {};
    const builder = {
        add(routes, prefix) {
            addRoutes(routeMap, routes, prefix);
            return builder;
        },
        get routes() {
            return routeMap;
        },
    };
    return builder;
}
// Singleton route map instance - populated incrementally as routes are encountered
let globalRouteMap = {};
// Cached complete manifest - includes all routes (including lazy includes)
// Set from runtime cache or build-time import
let cachedManifest = null;
// Pre-computed route entries from build-time prefix tree leaf nodes.
// Used by evaluateLazyEntry() to skip running the handler for route matching.
let cachedPrecomputedEntries = null;
/**
 * Register the route map globally for reverse to use at runtime
 *
 * Call this after building your route map to make it available to reverse.
 * Routes are merged with any existing registered routes.
 *
 * @param map - The route map to register
 *
 * @example
 * ```typescript
 * const routeMap = createRouteMap()
 *   .add(homeRoutes)
 *   .add(blogRoutes, "blog");
 *
 * registerRouteMap(routeMap.routes);
 * ```
 */
export function registerRouteMap(map) {
    // Always merge with existing map (don't replace)
    globalRouteMap = { ...globalRouteMap, ...map };
}
/**
 * Get the globally registered route map
 *
 * Used internally by reverse to resolve route names to URLs at runtime.
 * Returns the cached manifest if available (complete with lazy includes),
 * otherwise returns the runtime-accumulated route map.
 *
 * @returns The registered route map
 */
export function getGlobalRouteMap() {
    // Cached manifest is complete (includes lazy routes), so prefer it
    if (cachedManifest) {
        return cachedManifest;
    }
    return globalRouteMap;
}
/**
 * Set the cached manifest (for runtime cache integration)
 *
 * This sets the complete route manifest from a runtime cache.
 * The cached manifest includes all routes (including lazy includes)
 * and takes precedence over the incrementally-built globalRouteMap.
 *
 * @param manifest - The complete route manifest to cache
 */
export function setCachedManifest(manifest) {
    cachedManifest = manifest;
}
/**
 * Check if a cached manifest is loaded
 *
 * @returns true if a complete manifest is available
 */
export function hasCachedManifest() {
    return cachedManifest !== null;
}
/**
 * Clear the cached manifest (for testing)
 */
export function clearCachedManifest() {
    cachedManifest = null;
}
/**
 * Set pre-computed route entries from build-time data.
 *
 * Each entry corresponds to a leaf node in the prefix tree (no nested includes).
 * evaluateLazyEntry() checks these before running the handler, avoiding the
 * 5-50ms cost of handler evaluation for route matching on the first request.
 *
 * @param entries - Array of { staticPrefix, routes } from build-time prefix tree leaves
 */
export function setPrecomputedEntries(entries) {
    cachedPrecomputedEntries = entries;
}
/**
 * Get pre-computed route entries (if available)
 */
export function getPrecomputedEntries() {
    return cachedPrecomputedEntries;
}
// Route trie for O(path_length) matching at runtime.
// Built at build time from the route manifest and serialized into the virtual module.
let cachedRouteTrie = null;
export function setRouteTrie(trie) {
    cachedRouteTrie = trie;
}
export function getRouteTrie() {
    return cachedRouteTrie;
}
// Per-router isolated data: each router gets its own manifest, trie, and
// precomputed entries so multi-router setups (e.g. site + admin via
// createHostRouter()) don't see each other's routes.
const perRouterManifestMap = new Map();
const perRouterTrieMap = new Map();
const perRouterPrecomputedEntriesMap = new Map();
export function setRouterManifest(routerId, manifest) {
    perRouterManifestMap.set(routerId, manifest);
}
export function getRouterManifest(routerId) {
    return perRouterManifestMap.get(routerId);
}
export function setRouterTrie(routerId, trie) {
    perRouterTrieMap.set(routerId, trie);
}
export function getRouterTrie(routerId) {
    return perRouterTrieMap.get(routerId);
}
export function setRouterPrecomputedEntries(routerId, entries) {
    perRouterPrecomputedEntriesMap.set(routerId, entries);
}
export function getRouterPrecomputedEntries(routerId) {
    return perRouterPrecomputedEntriesMap.get(routerId);
}
// Lazy loader registry: per-router manifest modules are loaded on first request
// via import() to keep startup fast and allow Rollup to code-split per router.
const routerManifestLoaders = new Map();
export function registerRouterManifestLoader(routerId, loader) {
    routerManifestLoaders.set(routerId, loader);
}
export async function ensureRouterManifest(routerId) {
    if (perRouterManifestMap.has(routerId))
        return;
    const loader = routerManifestLoaders.get(routerId);
    if (loader) {
        const mod = await loader();
        if (mod.manifest)
            perRouterManifestMap.set(routerId, mod.manifest);
        if (mod.trie)
            perRouterTrieMap.set(routerId, mod.trie);
        if (mod.precomputedEntries)
            perRouterPrecomputedEntriesMap.set(routerId, mod.precomputedEntries);
        routerManifestLoaders.delete(routerId);
    }
}
// Dev-mode manifest readiness gate.
// The Vite discovery plugin calls setManifestReadyPromise() before starting
// discovery, and resolves it when discovery completes. The handler awaits
// waitForManifestReady() on first request if the manifest isn't yet available.
let manifestReadyPromise = null;
export function setManifestReadyPromise(promise) {
    manifestReadyPromise = promise;
}
export function waitForManifestReady() {
    return manifestReadyPromise;
}
// Global search schema map: route name -> search schema descriptor.
// Populated by path() when a search option is provided.
const globalSearchSchemas = new Map();
export function registerSearchSchema(routeName, schema) {
    globalSearchSchemas.set(routeName, schema);
}
export function getSearchSchema(routeName) {
    return globalSearchSchemas.get(routeName);
}
//# sourceMappingURL=route-map-builder.js.map