/**
 * Runtime Trie Matching
 *
 * Walks the pre-built trie by path segments in O(path_length) time.
 * Falls back to null when no match is found (caller uses regex fallback).
 */
/**
 * Try to match a pathname against the trie.
 * Returns null if no match found (caller should fall back to regex).
 */
export function tryTrieMatch(trie, pathname) {
    if (!trie)
        return null;
    // Split pathname into segments, filtering empty strings from leading/trailing slashes
    const pathnameHasTrailingSlash = pathname.length > 1 && pathname.endsWith("/");
    const normalizedPath = pathnameHasTrailingSlash ? pathname.slice(0, -1) : pathname;
    // Handle root path
    if (normalizedPath === "" || normalizedPath === "/") {
        if (trie.r) {
            return validateAndBuild(trie.r, [], undefined, pathname, pathnameHasTrailingSlash);
        }
        return null;
    }
    // Remove leading slash and split
    const segments = normalizedPath.slice(1).split("/");
    // Try exact match with normalized path (no trailing slash)
    const result = walkTrie(trie, segments, 0, []);
    if (result) {
        return validateAndBuild(result.leaf, result.paramValues, result.wildcardValue, pathname, pathnameHasTrailingSlash);
    }
    return null;
}
/**
 * Walk the trie by segments with priority: static > param > wildcard.
 * Uses backtracking to try all possible matches.
 */
function walkTrie(node, segments, index, paramValues) {
    // All segments consumed: check for terminal
    if (index === segments.length) {
        if (node.r) {
            return { leaf: node.r, paramValues };
        }
        return null;
    }
    const segment = segments[index];
    // Priority 1: Static match
    if (node.s?.[segment]) {
        const result = walkTrie(node.s[segment], segments, index + 1, paramValues);
        if (result)
            return result;
    }
    // Priority 2: Param match
    if (node.p) {
        const result = walkTrie(node.p.c, segments, index + 1, [
            ...paramValues,
            segment,
        ]);
        if (result)
            return result;
    }
    // Priority 3: Wildcard match (consumes rest)
    if (node.w) {
        const rest = segments.slice(index).join("/");
        return {
            leaf: node.w,
            paramValues,
            wildcardValue: rest,
        };
    }
    return null;
}
/**
 * Post-match: validate constraints and handle trailing slash logic.
 */
function validateAndBuild(leaf, paramValues, wildcardValue, originalPathname, pathnameHasTrailingSlash) {
    // Build named params by zipping leaf.pa with positional paramValues
    const params = {};
    if (leaf.pa) {
        for (let i = 0; i < leaf.pa.length && i < paramValues.length; i++) {
            params[leaf.pa[i]] = paramValues[i];
        }
    }
    // Add wildcard param (wildcard leaves have pn from TrieNode.w type)
    if (wildcardValue !== undefined && "pn" in leaf) {
        params[leaf.pn] = wildcardValue;
    }
    // Validate constraints
    if (leaf.cv) {
        for (const [paramName, allowed] of Object.entries(leaf.cv)) {
            const value = params[paramName];
            if (value !== undefined && value !== "" && !allowed.includes(value)) {
                return null;
            }
        }
    }
    // Fill in empty strings for optional params that weren't matched
    if (leaf.op) {
        for (const name of leaf.op) {
            if (!(name in params)) {
                params[name] = "";
            }
        }
    }
    // Trailing slash handling
    const tsMode = leaf.ts;
    let redirectTo;
    if (tsMode === "always" && !pathnameHasTrailingSlash && originalPathname !== "/") {
        redirectTo = originalPathname + "/";
    }
    else if (tsMode === "never" && pathnameHasTrailingSlash) {
        redirectTo = originalPathname.slice(0, -1);
    }
    return {
        routeKey: leaf.n,
        sp: leaf.sp,
        params,
        optionalParams: leaf.op,
        ancestry: leaf.a,
        ...(redirectTo ? { redirectTo } : {}),
        ...(leaf.pr ? { pr: true } : {}),
        ...(leaf.pt ? { pt: true } : {}),
        ...(leaf.rt ? { responseType: leaf.rt } : {}),
        ...(leaf.nv ? { negotiateVariants: leaf.nv } : {}),
        ...(leaf.rf ? { rscFirst: true } : {}),
    };
}
//# sourceMappingURL=trie-matching.js.map