// engine/workers/handlers/code-map.ts — Builds codebase structure map (SPEC-078 AC-08)
import { readFile, readdir, stat } from 'node:fs/promises';
import { join, extname, relative } from 'node:path';
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
const IGNORE_DIRS = new Set([
    'node_modules',
    '.git',
    'dist',
    'build',
    '__pycache__',
    'target',
    '.venv',
    'vendor',
    'coverage',
]);
const CODE_EXTS = new Set(['.ts', '.tsx', '.js', '.jsx', '.py', '.go', '.rs', '.java', '.kt']);
const ENTRY_POINT_NAMES = new Set([
    'main',
    'index',
    'app',
    'server',
    'mod',
    'lib',
    'main.ts',
    'index.ts',
    'app.ts',
    'server.ts',
    'main.py',
    '__main__.py',
    'app.py',
    'main.go',
    'main.rs',
    'lib.rs',
]);
// ---------------------------------------------------------------------------
// File collection
// ---------------------------------------------------------------------------
async function collectFiles(dir, files) {
    let entries;
    try {
        entries = await readdir(dir);
    }
    catch {
        return;
    }
    for (const entry of entries) {
        if (IGNORE_DIRS.has(entry)) {
            continue;
        }
        const fullPath = join(dir, entry);
        let st;
        try {
            st = await stat(fullPath);
        }
        catch {
            continue;
        }
        if (st.isDirectory()) {
            await collectFiles(fullPath, files);
        }
        else if (st.isFile() && CODE_EXTS.has(extname(fullPath))) {
            files.push(fullPath);
        }
    }
}
// ---------------------------------------------------------------------------
// Export detection — pattern-table approach to keep complexity low
// ---------------------------------------------------------------------------
const TS_EXPORT_PATTERNS = [
    { regex: /export\s+(?:async\s+)?function\s+(\w+)/, kind: 'function' },
    { regex: /export\s+class\s+(\w+)/, kind: 'class' },
    { regex: /export\s+(?:type|interface)\s+(\w+)/, kind: 'type' },
    { regex: /export\s+const\s+(\w+)/, kind: 'const' },
];
const JAVA_EXPORT_PATTERNS = [
    { regex: /public\s+(?:static\s+)?(?:\w+\s+)+(\w+)\s*\(/, kind: 'method' },
];
const EXPORT_PATTERNS = {
    '.ts': TS_EXPORT_PATTERNS,
    '.tsx': TS_EXPORT_PATTERNS,
    '.js': TS_EXPORT_PATTERNS,
    '.jsx': TS_EXPORT_PATTERNS,
    '.py': [
        { regex: /^def\s+(\w+)/, kind: 'function', filter: (n) => !n.startsWith('_') },
        { regex: /^class\s+(\w+)/, kind: 'class' },
    ],
    '.go': [
        { regex: /^func\s+([A-Z]\w*)/, kind: 'function' },
        { regex: /^type\s+([A-Z]\w*)/, kind: 'type' },
    ],
    '.rs': [
        { regex: /^pub\s+(?:async\s+)?fn\s+(\w+)/, kind: 'function' },
        { regex: /^pub\s+struct\s+(\w+)/, kind: 'struct' },
    ],
    '.java': JAVA_EXPORT_PATTERNS,
    '.kt': JAVA_EXPORT_PATTERNS,
};
function detectExports(content, ext) {
    const results = [];
    const patterns = EXPORT_PATTERNS[ext];
    if (!patterns) {
        return results;
    }
    for (const line of content.split('\n')) {
        for (const p of patterns) {
            const m = p.regex.exec(line);
            if (m?.[1] && (!p.filter || p.filter(m[1]))) {
                results.push({ name: m[1], kind: p.kind });
            }
        }
    }
    return results;
}
// ---------------------------------------------------------------------------
// Import detection — pattern-table approach
// ---------------------------------------------------------------------------
const TS_IMPORT_PATTERN = { regex: /from\s+['"](\.[^'"]+)['"]/ };
const JAVA_IMPORT_PATTERN = {
    regex: /^import\s+(\S+)/,
    transform: (m) => m.replace(';', ''),
};
const IMPORT_PATTERNS = {
    '.ts': TS_IMPORT_PATTERN,
    '.tsx': TS_IMPORT_PATTERN,
    '.js': TS_IMPORT_PATTERN,
    '.jsx': TS_IMPORT_PATTERN,
    '.py': { regex: /^(?:from|import)\s+(\S+)/, filter: (m) => !m.startsWith('__') },
    '.go': { regex: /^\s*"([^"]+)"/ },
    '.rs': { regex: /^use\s+(\S+)/, transform: (m) => m.replace(';', '') },
    '.java': JAVA_IMPORT_PATTERN,
    '.kt': JAVA_IMPORT_PATTERN,
};
function detectImports(content, ext) {
    const results = [];
    const pattern = IMPORT_PATTERNS[ext];
    if (!pattern) {
        return results;
    }
    for (const line of content.split('\n')) {
        const m = pattern.regex.exec(line);
        if (!m?.[1]) {
            continue;
        }
        if (pattern.filter && !pattern.filter(m[1])) {
            continue;
        }
        const value = pattern.transform ? pattern.transform(m[1]) : m[1];
        results.push(value);
    }
    return results;
}
// ---------------------------------------------------------------------------
// Public handler
// ---------------------------------------------------------------------------
export async function runCodeMap(projectDir, _changedFiles) {
    const startedAt = new Date().toISOString();
    const start = Date.now();
    const findings = [];
    const allFiles = [];
    await collectFiles(projectDir, allFiles);
    // Count files by extension
    const extCounts = new Map();
    const entryPoints = [];
    for (const file of allFiles) {
        const ext = extname(file);
        extCounts.set(ext, (extCounts.get(ext) ?? 0) + 1);
        const base = file.split('/').pop() ?? '';
        const baseName = base.replace(extname(base), '');
        if (ENTRY_POINT_NAMES.has(base) || ENTRY_POINT_NAMES.has(baseName)) {
            entryPoints.push(relative(projectDir, file));
        }
    }
    // Build export and import maps
    let totalExports = 0;
    let totalImports = 0;
    for (const file of allFiles) {
        let content;
        try {
            content = await readFile(file, 'utf-8');
        }
        catch {
            continue;
        }
        const ext = extname(file);
        const exports = detectExports(content, ext);
        const imports = detectImports(content, ext);
        totalExports += exports.length;
        totalImports += imports.length;
    }
    // Summary findings
    const extSummary = Array.from(extCounts.entries())
        .sort(([, a], [, b]) => b - a)
        .map(([ext, count]) => `${ext}: ${String(count)}`)
        .join(', ');
    findings.push({
        severity: 'info',
        file: '',
        message: `Codebase: ${String(allFiles.length)} files (${extSummary})`,
        category: 'code-map',
    });
    findings.push({
        severity: 'info',
        file: '',
        message: `Total exports: ${String(totalExports)}, Total imports: ${String(totalImports)}`,
        category: 'code-map',
    });
    if (entryPoints.length > 0) {
        findings.push({
            severity: 'info',
            file: '',
            message: `Entry points: ${entryPoints.join(', ')}`,
            category: 'code-map',
        });
    }
    return {
        workerName: 'code-map',
        startedAt,
        completedAt: new Date().toISOString(),
        durationMs: Date.now() - start,
        status: 'success',
        findings,
        analyzedFiles: allFiles.length,
    };
}
//# sourceMappingURL=code-map.js.map