var _a;
import { AsyncLocalStorage } from "node:async_hooks";
import { invariant } from "../errors";
// Use a global symbol key so the AsyncLocalStorage instance survives HMR
// module re-evaluation. Without this, Vite's RSC module runner may create
// a new instance when context.ts is re-evaluated, while other modules still
// hold references to the old instance — causing getStore() to return
// undefined even inside a run() callback.
const RSC_CONTEXT_KEY = Symbol.for("rangojs-router:rsc-context");
export const RSCRouterContext = (_a = globalThis)[RSC_CONTEXT_KEY] ?? (_a[RSC_CONTEXT_KEY] = new AsyncLocalStorage());
export const getContext = () => {
    const context = RSCRouterContext;
    return {
        context,
        getOrCreateStore: (forRoute) => {
            let store = RSCRouterContext.getStore();
            if (!store) {
                store = {
                    manifest: new Map(),
                    namespace: "",
                    parent: null,
                    forRoute,
                    counters: {},
                    patterns: new Map(),
                    patternsByPrefix: new Map(),
                    trailingSlash: new Map(),
                    searchSchemas: new Map(),
                };
            }
            return store;
        },
        getStore: () => {
            const store = context.getStore();
            if (!store) {
                throw new Error("RSC Router context store is not available. Make sure to run within RSC Router context.");
            }
            return store;
        },
        getParent: () => {
            const store = context.getStore();
            if (!store) {
                return null;
            }
            return store.parent;
        },
        getNextIndex: (type) => {
            var _a;
            const store = context.getStore();
            invariant(store, "No context RSCRouterContext available");
            (_a = store.counters)[type] ?? (_a[type] = 0);
            const index = store.counters[type];
            store.counters[type] = index + 1;
            return `$${type}.${index}`;
        },
        getShortCode: (type) => {
            var _a, _b;
            const store = context.getStore();
            invariant(store, "No context RSCRouterContext available");
            const parent = store.parent;
            const prefix = type === "layout" ? "L" : type === "parallel" ? "P" : type === "loader" ? "D" : type === "cache" ? "C" : "R";
            const mountPrefix = store.mountIndex !== undefined ? `M${store.mountIndex}` : "";
            if (!parent) {
                // Root entry: prefix with mount index and use mount-scoped counter
                const counterKey = mountPrefix ? `${mountPrefix}_root_${type}` : `root_${type}`;
                (_a = store.counters)[counterKey] ?? (_a[counterKey] = 0);
                const index = store.counters[counterKey];
                store.counters[counterKey] = index + 1;
                return `${mountPrefix}${prefix}${index}`;
            }
            else {
                // Child entry: use parent-scoped counter (parent already has M prefix)
                const counterKey = `${parent.shortCode}_${type}`;
                (_b = store.counters)[counterKey] ?? (_b[counterKey] = 0);
                const index = store.counters[counterKey];
                store.counters[counterKey] = index + 1;
                return `${parent.shortCode}${prefix}${index}`;
            }
        },
        runWithStore: (store, namespace, parent, callback) => {
            return context.run({
                manifest: store.manifest,
                namespace,
                parent: parent || null,
                counters: store.counters,
                forRoute: store.forRoute,
                mountIndex: store.mountIndex,
                metrics: store.metrics,
                isSSR: store.isSSR,
                patterns: store.patterns,
                trailingSlash: store.trailingSlash,
                searchSchemas: store.searchSchemas,
                urlPrefix: store.urlPrefix,
                namePrefix: store.namePrefix,
                trackedIncludes: store.trackedIncludes,
            }, callback);
        },
        run: (namespace, parent, callback) => {
            const store = context.getStore();
            // Preserve parent counters to ensure globally unique shortCodes
            const counters = store?.counters || {};
            const manifest = store ? store.manifest : new Map();
            const patterns = store?.patterns || new Map();
            const trailingSlash = store?.trailingSlash || new Map();
            const searchSchemas = store?.searchSchemas || new Map();
            return context.run({
                manifest,
                namespace,
                parent: parent || null,
                counters,
                forRoute: store?.forRoute,
                mountIndex: store?.mountIndex,
                metrics: store?.metrics,
                isSSR: store?.isSSR,
                patterns,
                trailingSlash,
                searchSchemas,
                urlPrefix: store?.urlPrefix,
                namePrefix: store?.namePrefix,
                trackedIncludes: store?.trackedIncludes,
            }, callback);
        },
    };
};
/**
 * Run a callback with specific URL and name prefixes
 * Used by include() to apply prefixes to nested patterns
 */
export function runWithPrefixes(urlPrefix, namePrefix, callback) {
    const store = RSCRouterContext.getStore();
    if (!store) {
        throw new Error("runWithPrefixes must be called within router context");
    }
    // Combine prefixes if there are existing ones, avoiding double slashes
    let combinedUrlPrefix;
    if (store.urlPrefix) {
        if (store.urlPrefix.endsWith("/") && urlPrefix.startsWith("/")) {
            combinedUrlPrefix = store.urlPrefix + urlPrefix.slice(1);
        }
        else {
            combinedUrlPrefix = store.urlPrefix + urlPrefix;
        }
    }
    else {
        combinedUrlPrefix = urlPrefix;
    }
    const combinedNamePrefix = namePrefix
        ? store.namePrefix
            ? `${store.namePrefix}.${namePrefix}`
            : namePrefix
        : store.namePrefix;
    return RSCRouterContext.run({
        ...store,
        urlPrefix: combinedUrlPrefix,
        namePrefix: combinedNamePrefix,
    }, callback);
}
/**
 * Get current URL prefix from context
 */
export function getUrlPrefix() {
    const store = RSCRouterContext.getStore();
    return store?.urlPrefix || "";
}
/**
 * Get current name prefix from context
 */
export function getNamePrefix() {
    const store = RSCRouterContext.getStore();
    return store?.namePrefix;
}
// ============================================================================
//  Performance Metrics Helpers
// ============================================================================
/**
 * Track performance of a code block (no-op if metrics not enabled)
 * Returns a done() callback to mark completion and record duration
 *
 * @example
 * ```typescript
 * const done = track("route-matching");
 * // ... do work ...
 * done(); // Records duration
 * ```
 */
export function track(label) {
    const store = RSCRouterContext.getStore();
    // No-op if context unavailable or metrics not enabled
    if (!store?.metrics?.enabled) {
        return () => { };
    }
    const startTime = performance.now() - store.metrics.requestStart;
    return () => {
        const duration = performance.now() - store.metrics.requestStart - startTime;
        store.metrics.metrics.push({ label, duration, startTime });
    };
}
//# sourceMappingURL=context.js.map