"use strict";
/**
 * Route Auth Resolver
 *
 * Resolves authentication chains for discovered routes by combining
 * multiple auth signals: direct middleware, mount-level, global,
 * filesystem middleware, route hierarchy, and throwing auth helpers.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.resolveRouteAuth = resolveRouteAuth;
const middleware_detector_1 = require("./middleware-detector");
const route_hierarchy_1 = require("./route-hierarchy");
const utils_1 = require("./route-discovery/utils");
// ============================================================================
// Constants
// ============================================================================
/**
 * Pattern to identify auth-enforcing middleware.
 * Must be specific to avoid false positives on generic middleware names like
 * "verify" (could be challenge verification), "session" (could be session tracking).
 *
 * Strategy: Match "auth" as a prefix/component in any position (handles camelCase
 * like authMiddleware, passportAuth, isAuthenticated). Also match specific
 * non-auth-prefixed terms (verifyToken, jwtVerify, clerk, etc.).
 * Does NOT match generic "verify", "guard", "require", "session", "protect" alone.
 */
const AUTH_MIDDLEWARE_PATTERN = /auth|isAuthorized|isAuthenticated|passport|verifyToken|verifyJwt|jwtAuth|jwtVerify|bearerAuth|clerk/i;
const THROWING_AUTH_PATTERNS = [
    /getCurrentUser(?:Id)?\s*\(/,
    /auth\(\)\.protect/,
    /requireAuth\s*\(/,
    /getSession\s*\(/,
    /assertAuthenticated\s*\(/,
    /ensureAuth\s*\(/,
];
// ============================================================================
// Public API
// ============================================================================
/**
 * Resolve auth middleware for all routes in the route map.
 *
 * Resolution sources (priority order):
 * 1. Direct middleware on route definition (already populated by extractors)
 * 2. Mount-level middleware (app.use('/api', authMw))
 * 2.5. Cross-file mount auth (file B imported by A which has mount-level auth)
 * 3. Global middleware (app.use(authMw))
 * 4. Next.js filesystem middleware (via isRouteProtectedByMiddleware)
 * 5. Route hierarchy (via getRouteProtectionContext)
 * 6. Throwing auth helpers in handler body
 *
 * Returns a new RouteMap with authMiddleware populated.
 */
function resolveRouteAuth(routeMap, mountPoints, files, middlewareConfig, moduleGraph) {
    const fileContentMap = new Map(files.map(f => [f.path, f.content]));
    const resolvedRoutes = routeMap.routes.map(route => {
        const resolved = { ...route, authMiddleware: [...route.authMiddleware] };
        // 2. Mount-level middleware
        const mountAuth = findMountLevelAuth(route.path, mountPoints);
        for (const mw of mountAuth) {
            if (!resolved.authMiddleware.includes(mw)) {
                resolved.authMiddleware.push(mw);
            }
        }
        // 2.5. Cross-file mount auth (if module graph available)
        if (moduleGraph && resolved.authMiddleware.length === 0) {
            const crossFileAuth = findCrossFileMountAuth(route, moduleGraph, mountPoints);
            for (const mw of crossFileAuth) {
                if (!resolved.authMiddleware.includes(mw)) {
                    resolved.authMiddleware.push(mw);
                }
            }
        }
        // 3. Global middleware
        const globalAuth = findGlobalAuth(mountPoints);
        for (const mw of globalAuth) {
            if (!resolved.authMiddleware.includes(mw)) {
                resolved.authMiddleware.push(mw);
            }
        }
        // 4. Next.js middleware.ts protection (uses the full path matching from middleware-detector)
        if (middlewareConfig.hasAuthMiddleware) {
            const mwResult = (0, middleware_detector_1.isRouteProtectedByMiddleware)(route.path, middlewareConfig);
            if (mwResult.isProtected) {
                const mwLabel = `middleware.ts:${middlewareConfig.authType || 'unknown'}`;
                if (!resolved.authMiddleware.includes(mwLabel)) {
                    resolved.authMiddleware.push(mwLabel);
                }
            }
        }
        // 5. Route hierarchy (filesystem-based protection groups)
        const hierarchy = (0, route_hierarchy_1.getRouteProtectionContext)(route.filePath);
        if (hierarchy.isInProtectedHierarchy) {
            for (const source of hierarchy.protectionSource) {
                if (!resolved.authMiddleware.includes(source)) {
                    resolved.authMiddleware.push(source);
                }
            }
        }
        // 6. Throwing auth helpers in handler body
        const content = fileContentMap.get(route.filePath);
        if (content && resolved.authMiddleware.length === 0) {
            const handlerContent = extractHandlerContent(content, route.handlerLine);
            if (hasThrowingAuthHelper(handlerContent)) {
                resolved.authMiddleware.push('throwing_auth_helper');
            }
        }
        return resolved;
    });
    // Rebuild fileToRoutes
    const fileToRoutes = new Map();
    for (const route of resolvedRoutes) {
        const existing = fileToRoutes.get(route.filePath) || [];
        existing.push(route);
        fileToRoutes.set(route.filePath, existing);
    }
    return { routes: resolvedRoutes, fileToRoutes };
}
// ============================================================================
// Internal Helpers
// ============================================================================
/**
 * Find auth middleware from files that import the route's file.
 * If server.ts has app.use('/api', authMw, require('./routes/api')) and
 * routes/api.ts defines routes, those routes inherit the mount-level auth.
 */
function findCrossFileMountAuth(route, graph, mountPoints) {
    const authMiddleware = [];
    const node = graph.nodes.get(route.filePath);
    if (!node)
        return authMiddleware;
    // Check files that import this route's file
    for (const importerPath of node.importedBy) {
        // Find mount points in the importing file that have auth middleware
        const importerMounts = mountPoints.filter(mp => mp.filePath === importerPath);
        for (const mount of importerMounts) {
            if (mount.isGlobal)
                continue;
            // Check if the route path matches the mount path (with boundary check)
            if (route.path === mount.path || route.path.startsWith(mount.path + '/')) {
                const authMw = mount.middleware.filter(m => AUTH_MIDDLEWARE_PATTERN.test(m));
                for (const mw of authMw) {
                    if (!authMiddleware.includes(mw)) {
                        authMiddleware.push(`cross-file:${mw}`);
                    }
                }
            }
        }
    }
    return authMiddleware;
}
function findMountLevelAuth(routePath, mountPoints) {
    const authMiddleware = [];
    for (const mount of mountPoints) {
        if (mount.isGlobal)
            continue;
        // Check if the route path matches the mount path (with boundary check)
        if (routePath === mount.path || routePath.startsWith(mount.path + '/')) {
            const authMw = mount.middleware.filter(m => AUTH_MIDDLEWARE_PATTERN.test(m));
            authMiddleware.push(...authMw);
        }
    }
    return authMiddleware;
}
function findGlobalAuth(mountPoints) {
    const authMiddleware = [];
    for (const mount of mountPoints) {
        if (!mount.isGlobal)
            continue;
        const authMw = mount.middleware.filter(m => AUTH_MIDDLEWARE_PATTERN.test(m));
        authMiddleware.push(...authMw);
    }
    return authMiddleware;
}
function extractHandlerContent(content, handlerLine) {
    const lines = content.split('\n');
    const start = Math.max(0, handlerLine - 1);
    return (0, utils_1.extractBlock)(lines, start);
}
function hasThrowingAuthHelper(content) {
    return THROWING_AUTH_PATTERNS.some(p => p.test(content));
}
//# sourceMappingURL=route-auth-resolver.js.map