"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildKnowledgeGraph = buildKnowledgeGraph;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const ts = __importStar(require("typescript"));
// ─── Builder ───────────────────────────────────────────────────────────────
const IGNORE_DIRS = new Set(['node_modules', '.git', 'dist', 'build', '.next', '.nuxt', 'coverage', '__pycache__', '.fivo', 'cell-data', 'archived']);
function walkFiles(dir, files = []) {
    if (!fs.existsSync(dir))
        return files;
    try {
        const entries = fs.readdirSync(dir, { withFileTypes: true });
        for (const e of entries) {
            if (IGNORE_DIRS.has(e.name) || e.name.startsWith('.'))
                continue;
            const full = path.join(dir, e.name);
            if (e.isDirectory())
                walkFiles(full, files);
            else if (/\.(ts|tsx|js|jsx)$/i.test(e.name)) {
                try {
                    if (fs.statSync(full).size < 500_000)
                        files.push(full);
                }
                catch { }
            }
        }
    }
    catch { }
    return files;
}
function extractImports(filePath) {
    const imports = [];
    try {
        const content = fs.readFileSync(filePath, 'utf-8');
        const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);
        const visit = (node) => {
            if (ts.isImportDeclaration(node) && ts.isStringLiteral(node.moduleSpecifier)) {
                const importPath = node.moduleSpecifier.text;
                if (importPath.startsWith('.') || importPath.startsWith('/')) {
                    // Resolve relative import
                    const dir = path.dirname(filePath);
                    let resolved = path.resolve(dir, importPath);
                    // Try with extensions
                    const extensions = ['.ts', '.tsx', '.js', '.jsx', '/index.ts', '/index.js'];
                    for (const ext of extensions) {
                        if (fs.existsSync(resolved + ext)) {
                            imports.push(resolved + ext);
                            break;
                        }
                    }
                    // Also track unresolved imports
                    if (!imports.some(i => i.startsWith(resolved))) {
                        imports.push(resolved);
                    }
                }
            }
            ts.forEachChild(node, visit);
        };
        visit(sourceFile);
    }
    catch { }
    return imports;
}
function calculateComplexity(filePath) {
    try {
        const content = fs.readFileSync(filePath, 'utf-8');
        let score = 0;
        // Count branching points
        score += (content.match(/\bif\s*\(/g) || []).length * 2;
        score += (content.match(/\bfor\s*\(/g) || []).length * 2;
        score += (content.match(/\bwhile\s*\(/g) || []).length * 2;
        score += (content.match(/\bswitch\s*\(/g) || []).length * 2;
        score += (content.match(/\bcatch\s*\(/g) || []).length * 1;
        score += (content.match(/\bfunction\s+\w+/g) || []).length * 1;
        score += (content.match(/=>/g) || []).length * 0.5;
        return Math.round(score);
    }
    catch {
        return 0;
    }
}
function buildKnowledgeGraph(dirPath) {
    const files = walkFiles(dirPath);
    const fileMap = new Map();
    // Map relative paths
    for (const file of files) {
        fileMap.set(path.relative(dirPath, file), file);
        fileMap.set(file, file);
    }
    const nodes = [];
    const importedByMap = new Map();
    for (const file of files) {
        const relPath = path.relative(dirPath, file);
        const imports = extractImports(file);
        const resolvedImports = [];
        for (const imp of imports) {
            // Try to find matching file by basename + relative fallback
            const impBasename = path.basename(imp).replace(/\.(ts|tsx|js|jsx)$/, '');
            let matched = false;
            for (const [key, val] of fileMap) {
                const keyBasename = path.basename(key).replace(/\.(ts|tsx|js|jsx)$/, '');
                if (keyBasename === impBasename && (imp.includes(key) || val.includes(imp) || imp.endsWith(key) || val.endsWith(imp))) {
                    resolvedImports.push(path.relative(dirPath, val));
                    // Track reverse dependency
                    const rev = importedByMap.get(path.relative(dirPath, val)) || new Set();
                    rev.add(relPath);
                    importedByMap.set(path.relative(dirPath, val), rev);
                    matched = true;
                    break;
                }
            }
            // Also try direct path match
            if (!matched) {
                for (const [key, val] of fileMap) {
                    if (imp === key || imp === val) {
                        resolvedImports.push(path.relative(dirPath, val));
                        const rev = importedByMap.get(path.relative(dirPath, val)) || new Set();
                        rev.add(relPath);
                        importedByMap.set(path.relative(dirPath, val), rev);
                        break;
                    }
                }
            }
        }
        const complexity = calculateComplexity(file);
        const isEntryPoint = file.endsWith('index.ts') || file.endsWith('index.js') ||
            file.endsWith('main.ts') || file.endsWith('server.ts') ||
            file.endsWith('cli.ts');
        nodes.push({
            file: relPath,
            imports: resolvedImports,
            importedBy: [],
            complexity,
            isEntryPoint,
        });
    }
    // Fill importedBy
    for (const node of nodes) {
        node.importedBy = [...(importedByMap.get(node.file) || [])];
    }
    // Sort by coupling
    nodes.sort((a, b) => (b.imports.length + b.importedBy.length) - (a.imports.length + a.importedBy.length));
    const entryPoints = nodes.filter(n => n.isEntryPoint).map(n => n.file);
    const mostCoupled = nodes.slice(0, 5).map(n => n.file);
    const leastCoupled = nodes.slice(-5).map(n => n.file);
    // Modularity: ratio of internal imports vs total
    const totalImports = nodes.reduce((s, n) => s + n.imports.length, 0);
    const internalImports = nodes.reduce((s, n) => s + n.imports.filter(i => nodes.some(x => x.file === i)).length, 0);
    const modularityScore = totalImports > 0 ? Math.round((internalImports / totalImports) * 100) : 0;
    return { nodes, entryPoints, mostCoupled, leastCoupled, modularityScore };
}
//# sourceMappingURL=knowledge-graph-builder.js.map