import * as fs from 'node:fs';
import * as path from 'node:path';
const ROUTE_PATTERNS = [
    // Express/Koa/Hono: app.get('/path', handler) or router.post(...)
    {
        regex: /(?:app|router|server)\.(get|post|put|patch|delete|head|options|all)\s*\(\s*['"`]([^'"`]+)['"`](?:\s*,\s*(\w+))?/gi,
        methodGroup: 1,
        pathGroup: 2,
        handlerGroup: 3,
    },
    // Fastify: fastify.get('/path', opts, handler)
    {
        regex: /fastify\.(get|post|put|patch|delete|head|options)\s*\(\s*['"`]([^'"`]+)['"`]/gi,
        methodGroup: 1,
        pathGroup: 2,
    },
    // Next.js App Router: export async function GET/POST/PUT/DELETE
    {
        regex: /export\s+(?:async\s+)?function\s+(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\s*\(/gi,
        methodGroup: 1,
        pathGroup: -1, // derived from file path
    },
    // Django: path('url/', view)
    {
        regex: /path\s*\(\s*['"]([^'"]+)['"](?:\s*,\s*(\w+))?/gi,
        methodGroup: -1,
        pathGroup: 1,
        handlerGroup: 2,
        defaultMethod: 'ALL',
    },
    // Flask: @app.route('/path', methods=['GET'])
    {
        regex: /@(?:app|bp|blueprint)\.route\s*\(\s*['"]([^'"]+)['"]\s*(?:,\s*methods\s*=\s*\[['"](\w+)['"])?/gi,
        methodGroup: 2,
        pathGroup: 1,
    },
    // Go net/http: http.HandleFunc("/path", handler)
    {
        regex: /http\.(?:HandleFunc|Handle)\s*\(\s*['"]([^'"]+)['"](?:\s*,\s*(\w+))?/gi,
        methodGroup: -1,
        pathGroup: 1,
        handlerGroup: 2,
        defaultMethod: 'ALL',
    },
    // Gin: r.GET("/path", handler)
    {
        regex: /(?:r|g|router|group)\.(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\s*\(\s*['"]([^'"]+)['"](?:\s*,\s*(\w+))?/gi,
        methodGroup: 1,
        pathGroup: 2,
        handlerGroup: 3,
    },
    // Spring Boot: @GetMapping("/path"), @RequestMapping
    {
        regex: /@(Get|Post|Put|Patch|Delete|Request)Mapping\s*\(\s*(?:value\s*=\s*)?['"]([^'"]+)['"]/gi,
        methodGroup: 1,
        pathGroup: 2,
    },
];
const SOURCE_EXTENSIONS = new Set([
    '.ts',
    '.tsx',
    '.js',
    '.jsx',
    '.mjs',
    '.cjs',
    '.py',
    '.go',
    '.java',
    '.kt',
    '.rb',
]);
const IGNORE_DIRS = new Set([
    'node_modules',
    '.git',
    'dist',
    'build',
    'out',
    '.next',
    '.nuxt',
    'coverage',
    'vendor',
    '__pycache__',
]);
function collectSourceFiles(dir) {
    const results = [];
    const queue = [dir];
    while (queue.length > 0) {
        const current = queue.pop();
        if (!current) {
            continue;
        }
        let entries;
        try {
            entries = fs.readdirSync(current, { withFileTypes: true });
        }
        catch {
            continue;
        }
        for (const entry of entries) {
            if (IGNORE_DIRS.has(entry.name)) {
                continue;
            }
            const full = path.join(current, entry.name);
            if (entry.isDirectory()) {
                queue.push(full);
            }
            else if (entry.isFile() && SOURCE_EXTENSIONS.has(path.extname(entry.name))) {
                results.push(full);
            }
        }
    }
    return results;
}
function extractResource(routePath) {
    const segments = routePath.replace(/^\//, '').split('/');
    const first = segments[0] ?? '';
    // Strip params like :id or {id}
    return first.replace(/[:{].*$/, '') || 'root';
}
function normalizeMethod(raw) {
    const upper = raw.toUpperCase();
    if (upper === 'REQUEST') {
        return 'ALL';
    }
    return upper;
}
function derivePathFromFile(filePath, rootDir) {
    // Next.js convention: app/api/users/route.ts -> /api/users
    const rel = path.relative(rootDir, filePath);
    const dir = path.dirname(rel);
    return '/' + dir.replace(/\\/g, '/');
}
export function detectApiRoutes(rootDir) {
    const files = collectSourceFiles(rootDir);
    const routes = [];
    for (const file of files) {
        let content;
        try {
            content = fs.readFileSync(file, 'utf-8');
        }
        catch {
            continue;
        }
        for (const pattern of ROUTE_PATTERNS) {
            const regex = new RegExp(pattern.regex.source, pattern.regex.flags);
            let match;
            while ((match = regex.exec(content)) !== null) {
                const methodRaw = pattern.methodGroup === -1
                    ? (pattern.defaultMethod ?? 'ALL')
                    : (match[pattern.methodGroup] ?? 'ALL');
                const routePath = pattern.pathGroup === -1
                    ? derivePathFromFile(file, rootDir)
                    : (match[pattern.pathGroup] ?? '/');
                const handler = pattern.handlerGroup
                    ? (match[pattern.handlerGroup] ?? 'anonymous')
                    : 'anonymous';
                routes.push({
                    method: normalizeMethod(methodRaw),
                    path: routePath,
                    handler,
                    resource: extractResource(routePath),
                });
            }
        }
    }
    return routes.sort((a, b) => a.resource.localeCompare(b.resource) ||
        a.path.localeCompare(b.path) ||
        a.method.localeCompare(b.method));
}
//# sourceMappingURL=api-detector.js.map