"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.buildProjectProfile = buildProjectProfile;
exports.getProjectProfile = getProjectProfile;
exports.listProjectProfiles = listProjectProfiles;
exports.deleteProjectProfile = deleteProjectProfile;
exports.compareProjects = compareProjects;
exports.getProjectsDirectory = getProjectsDirectory;
exports.inferArchitecture = inferArchitecture;
exports.detectTestingStyle = detectTestingStyle;
exports.generateConventions = generateConventions;
exports.ensureProjectDnaTable = ensureProjectDnaTable;
exports.recordCloudArchitecture = recordCloudArchitecture;
exports.getCloudArchitecture = getCloudArchitecture;
exports.recordCloudConvention = recordCloudConvention;
exports.getCloudConventions = getCloudConventions;
exports.scanFiles = scanFiles;
exports.buildLanguageProfile = buildLanguageProfile;
exports.buildFrameworkProfile = buildFrameworkProfile;
exports.buildArchitectureProfile = buildArchitectureProfile;
exports.buildTestingProfile = buildTestingProfile;
exports.buildDependencyProfile = buildDependencyProfile;
exports.buildComplexityProfile = buildComplexityProfile;
exports.buildRiskProfile = buildRiskProfile;
exports.buildMaturityProfile = buildMaturityProfile;
exports.buildDevelopmentProfile = buildDevelopmentProfile;
exports.buildFingerprint = buildFingerprint;
exports.buildProjectDNA = buildProjectDNA;
exports.saveDNA = saveDNA;
exports.getDNA = getDNA;
exports.listDNA = listDNA;
exports.deleteDNA = deleteDNA;
exports.getDNAHistory = getDNAHistory;
exports.compareDNA = compareDNA;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const os = __importStar(require("os"));
const database_1 = require("../../06-memory/database/database");
const PROJECTS_DIR = path.join(os.homedir(), '.fivo', 'cell', 'projects');
const DNA_STORE_PATH = path.join(os.homedir(), '.fivo', 'cell', 'project_dna.json');
function ensureStoreDir() {
    const dir = path.dirname(DNA_STORE_PATH);
    if (!fs.existsSync(dir))
        fs.mkdirSync(dir, { recursive: true });
}
function ensureProjectsDir() {
    if (!fs.existsSync(PROJECTS_DIR))
        fs.mkdirSync(PROJECTS_DIR, { recursive: true });
}
function projectPath(projectId) {
    return path.join(PROJECTS_DIR, `${sanitizeId(projectId)}.json`);
}
function sanitizeId(id) {
    return id.replace(/[^a-zA-Z0-9_-]/g, '_');
}
// ─── LEGACY: Pattern-based profile functions ──────────────────────────
function buildProjectProfile(projectId, name, patterns) {
    ensureProjectsDir();
    const langMap = new Map();
    const catMap = new Map();
    const fwMap = new Map();
    const seqMap = new Map();
    const totalSignals = patterns.reduce((s, p) => s + p.signals.total, 0);
    const totalConf = patterns.reduce((s, p) => s + p.confidence.mean, 0);
    for (const p of patterns) {
        for (const c of p.conditions) {
            if (c.type === 'language')
                langMap.set(c.value, (langMap.get(c.value) || 0) + 1);
            if (c.type === 'framework')
                fwMap.set(c.value, (fwMap.get(c.value) || 0) + 1);
        }
        catMap.set(p.category, (catMap.get(p.category) || 0) + 1);
        const seqKey = `${p.from}|${p.to}`;
        seqMap.set(seqKey, (seqMap.get(seqKey) || 0) + 1);
    }
    const total = patterns.length || 1;
    const languages = Array.from(langMap.entries())
        .map(([language, count]) => ({ language, count, pct: Math.round((count / total) * 100) }))
        .sort((a, b) => b.count - a.count);
    const categories = Array.from(catMap.entries())
        .map(([category, count]) => ({ category, count, pct: Math.round((count / total) * 100) }))
        .sort((a, b) => b.count - a.count);
    const profile = {
        projectId, name,
        primaryLanguage: languages[0]?.language || 'unknown', languages, categories,
        frameworks: Array.from(fwMap.entries()).map(([framework, count]) => ({ framework, count })).sort((a, b) => b.count - a.count),
        totalPatterns: patterns.length, totalSignals,
        topPatterns: patterns.sort((a, b) => b.signals.total - a.signals.total).slice(0, 10).map((p) => {
            const total = p.signals.positive + p.signals.negative;
            return { patternId: p.patternId, description: p.description, acceptRate: total > 0 ? p.signals.positive / total : 0 };
        }),
        patternSequences: Array.from(seqMap.entries()).map(([k, count]) => {
            const [from, to] = k.split('|');
            return { from, to, count };
        }).sort((a, b) => b.count - a.count).slice(0, 20),
        averageConfidence: patterns.length > 0 ? totalConf / patterns.length : 0,
        createdAt: Date.now(), updatedAt: Date.now(),
    };
    fs.writeFileSync(projectPath(projectId), JSON.stringify(profile, null, 2), 'utf-8');
    return profile;
}
function getProjectProfile(projectId) {
    try {
        const fp = projectPath(projectId);
        if (!fs.existsSync(fp))
            return null;
        return JSON.parse(fs.readFileSync(fp, 'utf-8'));
    }
    catch {
        return null;
    }
}
function listProjectProfiles() {
    ensureProjectsDir();
    try {
        return fs.readdirSync(PROJECTS_DIR).filter((f) => f.endsWith('.json')).map((f) => f.replace('.json', ''));
    }
    catch {
        return [];
    }
}
function deleteProjectProfile(projectId) {
    try {
        const fp = projectPath(projectId);
        if (fs.existsSync(fp)) {
            fs.unlinkSync(fp);
            return true;
        }
        return false;
    }
    catch {
        return false;
    }
}
function compareProjects(projectA, projectB) {
    const profileA = getProjectProfile(projectA);
    const profileB = getProjectProfile(projectB);
    if (!profileA || !profileB) {
        return { projectA, projectB, similarity: 0, sharedLanguages: [], sharedCategories: [], sharedPatterns: [], divergences: ['One or both projects not found'] };
    }
    const sharedLangs = profileA.languages.filter((l) => profileB.languages.some((lb) => lb.language === l.language)).map((l) => l.language);
    const sharedCats = profileA.categories.filter((c) => profileB.categories.some((cb) => cb.category === c.category)).map((c) => c.category);
    const sharedPatterns = profileA.topPatterns.filter((p) => profileB.topPatterns.some((pb) => pb.patternId === p.patternId)).map((p) => p.patternId);
    const allLangs = new Set([...profileA.languages.map((l) => l.language), ...profileB.languages.map((l) => l.language)]);
    const langOverlap = sharedLangs.length / (allLangs.size || 1);
    const allCats = new Set([...profileA.categories.map((c) => c.category), ...profileB.categories.map((c) => c.category)]);
    const catOverlap = sharedCats.length / (allCats.size || 1);
    const similarity = Math.round(((langOverlap + catOverlap) / 2) * 100);
    const divergences = [];
    if (profileA.primaryLanguage !== profileB.primaryLanguage)
        divergences.push(`Primary language differs: ${profileA.primaryLanguage} vs ${profileB.primaryLanguage}`);
    const uniqueA = profileA.categories.filter((c) => !profileB.categories.some((cb) => cb.category === c.category));
    const uniqueB = profileB.categories.filter((c) => !profileA.categories.some((ca) => ca.category === c.category));
    if (uniqueA.length > 0)
        divergences.push(`Unique categories in ${projectA}: ${uniqueA.map((c) => c.category).join(', ')}`);
    if (uniqueB.length > 0)
        divergences.push(`Unique categories in ${projectB}: ${uniqueB.map((c) => c.category).join(', ')}`);
    return { projectA, projectB, similarity, sharedLanguages: sharedLangs, sharedCategories: sharedCats, sharedPatterns, divergences };
}
function getProjectsDirectory() {
    return PROJECTS_DIR;
}
function inferArchitecture(patterns) {
    const evidence = [];
    const allDesc = patterns.map((p) => `${p.description} ${p.category}`.toLowerCase()).join(' ');
    if (/model|view|controller|route/.test(allDesc))
        evidence.push({ name: 'MVC (Model-View-Controller)', confidence: 0.7, evidence: ['Detected model/view/controller references'] });
    if (/service|repository|usecase|dto|entity/.test(allDesc))
        evidence.push({ name: 'Layered / Clean Architecture', confidence: 0.75, evidence: ['Detected service/repository/usecase layers'] });
    if (/component|hook|render|jsx|tsx/.test(allDesc))
        evidence.push({ name: 'Component-based (React/Vue)', confidence: 0.8, evidence: ['Detected components/hooks'] });
    if (/api|endpoint|handler|middleware/.test(allDesc))
        evidence.push({ name: 'API-first / Microservices', confidence: 0.65, evidence: ['Detected API/handler patterns'] });
    if (/pipe|compose|reduce|map|filter|immutable|pure/.test(allDesc))
        evidence.push({ name: 'Functional Programming', confidence: 0.6, evidence: ['Detected functional patterns'] });
    evidence.sort((a, b) => b.confidence - a.confidence);
    return { detectedPatterns: evidence, suggestedLabel: evidence[0]?.name || 'Unknown' };
}
function detectTestingStyle(patterns) {
    const all = patterns.map((p) => `${p.description} ${p.from} ${p.to}`).join(' ').toLowerCase();
    if (/describe|it\(|vitest/.test(all))
        return { framework: 'vitest', style: 'describe/it', location: 'co-located', confidence: 0.9 };
    if (/jest|expect\(|test\(/.test(all))
        return { framework: 'jest', style: 'test()', location: '__tests__', confidence: 0.85 };
    if (/mocha|assert\(/.test(all))
        return { framework: 'mocha', style: 'describe/it', location: 'tests/', confidence: 0.7 };
    if (/pytest|def test_/.test(all))
        return { framework: 'pytest', style: 'test()', location: 'tests/', confidence: 0.8 };
    return { framework: 'unknown', style: 'unknown', location: 'unknown', confidence: 0 };
}
function generateConventions(profile) {
    const suggestions = [];
    const lang = profile.primaryLanguage;
    if (lang === 'typescript' || lang === 'javascript') {
        suggestions.push({ type: 'editorconfig', content: 'root = true\n\n[*]\nindent_style = space\nindent_size = 2\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true', description: `2-space indentation recommended for ${lang}` });
        suggestions.push({ type: 'tsconfig', content: '{\n  "compilerOptions": {\n    "strict": true,\n    "esModuleInterop": true,\n    "skipLibCheck": true,\n    "forceConsistentCasingInFileNames": true\n  }\n}', description: 'Strict mode recommended based on project patterns' });
    }
    if (profile.languages.length > 1)
        suggestions.push({ type: 'prettier', content: '{\n  "semi": true,\n  "singleQuote": true,\n  "tabWidth": 2,\n  "trailingComma": "all"\n}', description: 'Multi-language project — Prettier for consistent formatting' });
    return suggestions;
}
// ─── CLOUD PROJECT DNA DB (SQLite) ────────────────────
function ensureProjectDnaTable() {
    const db = (0, database_1.getDb)();
    db.exec(`CREATE TABLE IF NOT EXISTS project_architectures (id INTEGER PRIMARY KEY AUTOINCREMENT, project_id TEXT NOT NULL, label TEXT NOT NULL, patterns TEXT NOT NULL)`);
    db.exec(`CREATE TABLE IF NOT EXISTS project_conventions (id INTEGER PRIMARY KEY AUTOINCREMENT, project_id TEXT NOT NULL, convention_type TEXT NOT NULL, suggestion TEXT NOT NULL, description TEXT)`);
}
function recordCloudArchitecture(projectId, label, patterns) {
    const db = (0, database_1.getDb)();
    db.prepare(`INSERT INTO project_architectures (project_id, label, patterns) VALUES (?, ?, ?)`).run(projectId, label, JSON.stringify(patterns));
}
function getCloudArchitecture(projectId) {
    const db = (0, database_1.getDb)();
    const row = db.prepare(`SELECT label, patterns FROM project_architectures WHERE project_id = ? ORDER BY id DESC LIMIT 1`).get(projectId);
    if (!row)
        return null;
    return { label: row.label, patterns: JSON.parse(row.patterns) };
}
function recordCloudConvention(projectId, type, suggestion, description) {
    const db = (0, database_1.getDb)();
    db.prepare(`INSERT INTO project_conventions (project_id, convention_type, suggestion, description) VALUES (?, ?, ?, ?)`).run(projectId, type, suggestion, description);
}
function getCloudConventions(projectId) {
    const db = (0, database_1.getDb)();
    const rows = db.prepare(`SELECT convention_type, suggestion FROM project_conventions WHERE project_id = ?`).all(projectId);
    return rows.map(r => ({ type: r.convention_type, suggestion: r.suggestion }));
}
// ═══════════════════════════════════════════════════════════════
// CHAPTER 5 — PROJECT DNA (File System based)
// ═══════════════════════════════════════════════════════════════
const EXT_TO_LANG = {
    ts: 'typescript', tsx: 'typescript', js: 'javascript', jsx: 'javascript',
    mjs: 'javascript', cjs: 'javascript', mts: 'typescript', cts: 'typescript',
    py: 'python', rb: 'ruby', go: 'go', rs: 'rust',
    java: 'java', kt: 'kotlin', scala: 'scala',
    swift: 'swift', m: 'objective-c', h: 'c', cpp: 'cpp', c: 'c', cs: 'csharp',
    php: 'php', vue: 'vue', svelte: 'svelte',
    html: 'html', css: 'css', scss: 'scss', less: 'less',
    yaml: 'yaml', yml: 'yaml', json: 'json', xml: 'xml', md: 'markdown',
    sh: 'shell', bash: 'shell', zsh: 'shell',
    sql: 'sql', graphql: 'graphql', prisma: 'prisma',
    dockerfile: 'dockerfile', tf: 'terraform', toml: 'toml',
};
const SKIP_DIRS = new Set(['node_modules', '.git', '.svn', '__pycache__', '.next', 'dist', 'build', '.cache', 'coverage', '.nyc_output', 'target', 'vendor', '.tox', '.eggs', 'egg-info', '.venv', 'venv', '.idea', '.vscode', '.terrafor']);
function scanFiles(rootDir, maxDepth = 20) {
    const results = [];
    function walk(dir, depth) {
        if (depth > maxDepth)
            return;
        let entries;
        try {
            entries = fs.readdirSync(dir, { withFileTypes: true });
        }
        catch {
            return;
        }
        for (const entry of entries) {
            const fullPath = path.join(dir, entry.name);
            if (entry.isDirectory()) {
                if (SKIP_DIRS.has(entry.name))
                    continue;
                walk(fullPath, depth + 1);
            }
            else if (entry.isFile()) {
                const relPath = path.relative(rootDir, fullPath);
                const parsed = path.parse(entry.name);
                const ext = parsed.ext.slice(1).toLowerCase();
                const baseName = parsed.name;
                const language = EXT_TO_LANG[ext] || ext;
                const normalized = relPath.replace(/\\/g, '/');
                const isTest = /\.(test|spec|e2e|integration)\./.test(normalized) || normalized.includes('__tests__') || normalized.includes('/test/') || normalized.includes('/tests/') || normalized.startsWith('test/') || normalized.startsWith('tests/');
                let lines = 0;
                let size = 0;
                try {
                    const stat = fs.statSync(fullPath);
                    size = stat.size;
                    if (size < 1024 * 1024) {
                        const content = fs.readFileSync(fullPath, 'utf-8');
                        lines = content.split('\n').length;
                    }
                }
                catch {
                    lines = 0;
                }
                results.push({ relativePath: relPath, fullPath, ext, lines, language, isTest, size });
            }
        }
    }
    walk(rootDir, 0);
    return results;
}
// ─── SYSTEM 1: LANGUAGE PROFILE ───────────────────────
function buildLanguageProfile(files) {
    const langMap = new Map();
    for (const f of files) {
        if (!langMap.has(f.language))
            langMap.set(f.language, { fileCount: 0, lineCount: 0, exts: new Set() });
        const entry = langMap.get(f.language);
        entry.fileCount++;
        entry.lineCount += f.lines;
        entry.exts.add(f.ext);
    }
    const totalFiles = files.length || 1;
    const languages = Array.from(langMap.entries())
        .map(([lang, data]) => ({
        language: lang, extensions: Array.from(data.exts), fileCount: data.fileCount,
        lineCount: data.lineCount, percentage: Math.round((data.fileCount / totalFiles) * 100),
    }))
        .sort((a, b) => b.fileCount - a.fileCount);
    const primaryLanguage = languages[0]?.language || 'unknown';
    const languagePurity = languages[0]?.percentage || 0;
    return { primaryLanguage, languages, languagePurity };
}
// ─── SYSTEM 2: FRAMEWORK PROFILE ──────────────────────
function detectFrameworkFromPackageJson(content) {
    const results = [];
    const frameworkKeywords = {
        'Next.js': ['next', 'next.js', 'nextjs'],
        'React': ['react', 'react-dom'],
        'Vue': ['vue', 'vue-router', 'nuxt'],
        'Angular': ['@angular/core', 'angular'],
        'Express': ['express'],
        'NestJS': ['@nestjs/core', 'nestjs'],
        'Fastify': ['fastify'],
        'Svelte': ['svelte', 'svelte-kit'],
        'Gatsby': ['gatsby'],
        'Nuxt': ['nuxt', 'nuxt3'],
        'Remix': ['@remix-run/react', 'remix'],
        'Astro': ['astro'],
    };
    for (const [name, keywords] of Object.entries(frameworkKeywords)) {
        for (const kw of keywords) {
            if (content.includes(`"${kw}"`)) {
                results.push({ name, confidence: 0.8, evidence: [`Found dependency "${kw}"`] });
                break;
            }
        }
    }
    return results;
}
function detectFrameworkFromRequirementsTxt(content) {
    const results = [];
    const lines = content.toLowerCase().split('\n');
    const frameworks = {
        'FastAPI': ['fastapi'],
        'Django': ['django'],
        'Flask': ['flask'],
        'Starlette': ['starlette'],
        'Tornado': ['tornado'],
        'AIOHTTP': ['aiohttp'],
        'SQLAlchemy': ['sqlalchemy'],
    };
    for (const [name, keywords] of Object.entries(frameworks)) {
        for (const kw of keywords) {
            if (lines.some(l => l.includes(kw))) {
                results.push({ name, confidence: 0.7, evidence: [`Found dependency "${kw}" in requirements`] });
                break;
            }
        }
    }
    return results;
}
function detectFrameworkFromGoMod(content) {
    const results = [];
    const frameworks = {
        'Gin': ['github.com/gin-gonic/gin'],
        'Fiber': ['github.com/gofiber/fiber'],
        'Echo': ['github.com/labstack/echo'],
        'Chi': ['github.com/go-chi/chi'],
        'Mux': ['github.com/gorilla/mux'],
    };
    for (const [name, keywords] of Object.entries(frameworks)) {
        for (const kw of keywords) {
            if (content.includes(kw)) {
                results.push({ name, confidence: 0.7, evidence: [`Found dependency "${kw}" in go.mod`] });
                break;
            }
        }
    }
    return results;
}
function buildFrameworkProfile(files, rootDir) {
    const allEvidence = [];
    const packageJson = files.find(f => f.relativePath === 'package.json');
    if (packageJson) {
        try {
            const content = fs.readFileSync(packageJson.fullPath, 'utf-8');
            allEvidence.push(...detectFrameworkFromPackageJson(content));
        }
        catch { }
    }
    const requirementsTxt = files.find(f => f.relativePath === 'requirements.txt');
    if (requirementsTxt) {
        try {
            const content = fs.readFileSync(requirementsTxt.fullPath, 'utf-8');
            allEvidence.push(...detectFrameworkFromRequirementsTxt(content));
        }
        catch { }
    }
    const goMod = files.find(f => f.relativePath === 'go.mod');
    if (goMod) {
        try {
            const content = fs.readFileSync(goMod.fullPath, 'utf-8');
            allEvidence.push(...detectFrameworkFromGoMod(content));
        }
        catch { }
    }
    const seen = new Set();
    const unique = [];
    for (const ev of allEvidence) {
        if (!seen.has(ev.name)) {
            seen.add(ev.name);
            unique.push(ev);
        }
    }
    unique.sort((a, b) => b.confidence - a.confidence);
    const primaryFramework = unique[0]?.name || null;
    return { frameworks: unique, primaryFramework };
}
// ─── SYSTEM 3: ARCHITECTURE PROFILE ───────────────────
const ARCH_SIGNATURES = [
    { type: 'layered', dirs: ['controllers', 'services', 'repositories', 'middleware', 'routes'], keywords: ['controller', 'service', 'repository'] },
    { type: 'mvc', dirs: ['models', 'views', 'controllers'], keywords: ['model', 'view', 'controller'] },
    { type: 'feature-based', dirs: ['features', 'modules', 'domains'], keywords: ['feature', 'module'] },
    { type: 'microservice', dirs: ['services', 'api-gateway', 'gateway'], keywords: ['endpoint', 'handler', 'microservice'] },
    { type: 'modular-monolith', dirs: ['modules', 'contexts', 'bounded-contexts'], keywords: ['module', 'context', 'bounded'] },
    { type: 'hexagonal', dirs: ['adapters', 'ports', 'domain', 'infrastructure'], keywords: ['adapter', 'port', 'hexagon'] },
    { type: 'clean-architecture', dirs: ['use-cases', 'entities', 'interface-adapters', 'frameworks-drivers'], keywords: ['usecase', 'entity', 'interface'] },
    { type: 'monolith', dirs: ['app', 'src', 'lib'], keywords: [] },
];
function buildArchitectureProfile(files, rootDir) {
    const dirs = new Set();
    for (const f of files) {
        const parts = f.relativePath.split(/[/\\]/);
        for (let i = 0; i < parts.length - 1; i++)
            dirs.add(parts[i].toLowerCase());
    }
    const candidates = [];
    for (const sig of ARCH_SIGNATURES) {
        let score = 0;
        const evidence = [];
        for (const d of sig.dirs) {
            if (dirs.has(d)) {
                score += 0.25;
                evidence.push(`Found directory: ${d}`);
            }
        }
        const allPaths = files.map(f => f.relativePath.toLowerCase()).join(' ');
        for (const kw of sig.keywords) {
            if (allPaths.includes(kw)) {
                score += 0.15;
                evidence.push(`Found ${kw} references in file paths`);
            }
        }
        if (evidence.length > 0) {
            candidates.push({ type: sig.type, confidence: Math.min(score, 0.95), evidence });
        }
    }
    candidates.sort((a, b) => b.confidence - a.confidence);
    const architecture = candidates[0]?.type || 'unknown';
    const confidence = candidates[0]?.confidence || 0;
    const hasApiLayer = dirs.has('api') || dirs.has('routes') || dirs.has('endpoints') || files.some(f => f.relativePath.includes('/api/'));
    const hasServiceLayer = dirs.has('services') || dirs.has('service');
    const hasDataLayer = dirs.has('repositories') || dirs.has('data') || dirs.has('models') || dirs.has('entities');
    return { architecture, confidence, candidates, hasApiLayer, hasServiceLayer, hasDataLayer };
}
// ─── SYSTEM 4: TESTING DNA ────────────────────────────
const TEST_FRAMEWORK_MAP = [
    { framework: 'jest', configFiles: ['jest.config.js', 'jest.config.ts', 'jest.config.json'], indicators: ['jest'] },
    { framework: 'vitest', configFiles: ['vitest.config.ts', 'vitest.config.js'], indicators: ['vitest'] },
    { framework: 'playwright', configFiles: ['playwright.config.ts', 'playwright.config.js'], indicators: ['playwright'] },
    { framework: 'cypress', configFiles: ['cypress.config.js', 'cypress.config.ts', 'cypress.json'], indicators: ['cypress'] },
    { framework: 'mocha', configFiles: ['.mocharc.js', '.mocharc.json'], indicators: ['mocha'] },
    { framework: 'pytest', configFiles: ['pytest.ini', 'pyproject.toml'], indicators: ['pytest'] },
    { framework: 'unittest', configFiles: [], indicators: ['unittest', 'test_'] },
    { framework: 'go-test', configFiles: ['go.mod'], indicators: ['_test.go'] },
];
function buildTestingProfile(files, rootDir) {
    const testFiles = files.filter(f => f.isTest);
    const sourceFiles = files.filter(f => !f.isTest && f.ext !== '' && f.ext !== 'md' && f.ext !== 'json' && f.ext !== 'yaml' && f.ext !== 'yml');
    const testFileCount = testFiles.length;
    const sourceFileCount = sourceFiles.length;
    const testToSourceRatio = sourceFileCount > 0 ? Math.round((testFileCount / sourceFileCount) * 100) / 100 : 0;
    const frameworks = [];
    const fwSet = new Set();
    for (const fw of TEST_FRAMEWORK_MAP) {
        const hasConfig = fw.configFiles.some(cf => files.some(f => f.relativePath === cf));
        let hasIndicator = false;
        if (fw.framework === 'go-test') {
            hasIndicator = files.some(f => f.relativePath.endsWith('_test.go'));
        }
        else if (fw.framework === 'pytest') {
            hasIndicator = files.some(f => f.relativePath.endsWith('.py') && (f.relativePath.includes('test_') || f.relativePath.includes('_test')));
        }
        else if (fw.framework === 'unittest') {
            hasIndicator = files.some(f => f.relativePath.includes('test_') && f.relativePath.endsWith('.py'));
        }
        if (hasConfig || hasIndicator) {
            if (!fwSet.has(fw.framework)) {
                fwSet.add(fw.framework);
                frameworks.push(fw.framework);
            }
        }
    }
    const coverageScore = Math.min(Math.round(testToSourceRatio * 100), 100);
    const cultureScore = Math.min((testFileCount > 0 ? 30 : 0) +
        (frameworks.length > 0 ? 20 : 0) +
        (testToSourceRatio >= 0.3 ? 25 : testToSourceRatio >= 0.1 ? 15 : 5) +
        (testFiles.some(f => f.lines > 20) ? 25 : 10), 100);
    const maturity = testFileCount === 0 ? 'none' : testToSourceRatio < 0.1 ? 'minimal' : testToSourceRatio < 0.3 ? 'moderate' : testToSourceRatio < 0.5 ? 'strong' : 'comprehensive';
    return { frameworks, testFileCount, sourceFileCount, testToSourceRatio, coverageScore, cultureScore, maturity };
}
// ─── SYSTEM 5: DEPENDENCY DNA ─────────────────────────
function buildDependencyProfile(files, rootDir) {
    let depCount = 0;
    let devDepCount = 0;
    let hasPackageManager = false;
    let packageManager = null;
    const pkgJson = files.find(f => f.relativePath === 'package.json');
    if (pkgJson) {
        try {
            const content = JSON.parse(fs.readFileSync(pkgJson.fullPath, 'utf-8'));
            depCount = Object.keys(content.dependencies || {}).length;
            devDepCount = Object.keys(content.devDependencies || {}).length;
            hasPackageManager = true;
            packageManager = 'npm';
            if (files.some(f => f.relativePath === 'yarn.lock'))
                packageManager = 'yarn';
            else if (files.some(f => f.relativePath === 'pnpm-lock.yaml'))
                packageManager = 'pnpm';
        }
        catch { }
    }
    const goMod = files.find(f => f.relativePath === 'go.mod');
    if (goMod) {
        hasPackageManager = true;
        packageManager = packageManager || 'go-modules';
        try {
            const content = fs.readFileSync(goMod.fullPath, 'utf-8');
            const requireLines = content.split('\n').filter(l => l.trim().startsWith('require') || (l.trim().startsWith('github.com') && !l.trim().startsWith('//')));
            depCount += requireLines.length;
        }
        catch { }
    }
    const reqTxt = files.find(f => f.relativePath === 'requirements.txt');
    if (reqTxt) {
        hasPackageManager = true;
        packageManager = packageManager || 'pip';
        try {
            const content = fs.readFileSync(reqTxt.fullPath, 'utf-8');
            depCount += content.split('\n').filter(l => l.trim() && !l.startsWith('#') && !l.startsWith('-')).length;
        }
        catch { }
    }
    const cargoToml = files.find(f => f.relativePath === 'Cargo.toml');
    if (cargoToml) {
        hasPackageManager = true;
        packageManager = packageManager || 'cargo';
        try {
            const content = fs.readFileSync(cargoToml.fullPath, 'utf-8');
            const depLines = content.split('\n').filter(l => l.trim().startsWith('[') && l.includes('dependencies'));
            depCount += depLines.length;
        }
        catch { }
    }
    const totalDeps = depCount + devDepCount;
    const dependencyComplexity = totalDeps === 0 ? 'low' : totalDeps < 50 ? 'low' : totalDeps < 150 ? 'medium' : totalDeps < 300 ? 'high' : 'extreme';
    const dependencyRisk = totalDeps === 0 ? 0 : Math.min(Math.round((totalDeps / 300) * 100), 100);
    return { totalDependencies: depCount, totalDevDependencies: devDepCount, dependencyCount: totalDeps, dependencyComplexity, dependencyRisk, hasPackageManager, packageManager };
}
// ─── SYSTEM 6: COMPLEXITY DNA ─────────────────────────
function buildComplexityProfile(files, rootDir) {
    const srcFiles = files.filter(f => f.ext !== '' && !f.isTest);
    const totalFiles = srcFiles.length;
    const totalLines = srcFiles.reduce((s, f) => s + f.lines, 0);
    const averageFileSize = totalFiles > 0 ? Math.round(totalLines / totalFiles) : 0;
    const largestFiles = srcFiles.sort((a, b) => b.lines - a.lines).slice(0, 10).map(f => ({ path: f.relativePath, lines: f.lines }));
    const complexity = totalFiles === 0 ? 'low' : totalFiles < 50 ? 'low' : totalFiles < 200 ? 'medium' : totalFiles < 500 ? 'high' : 'extreme';
    return { totalFiles, totalLines, averageFileSize, largestFiles, complexity };
}
// ─── SYSTEM 7: RISK DNA ───────────────────────────────
function buildRiskProfile(files, rootDir, profiles) {
    const riskFactors = [];
    let riskScore = 0;
    if (profiles.testing.testFileCount === 0) {
        riskFactors.push({ factor: 'No tests', severity: 25, description: 'Project has zero test files' });
        riskScore += 25;
    }
    else if (profiles.testing.coverageScore < 10) {
        riskFactors.push({ factor: 'Low test coverage', severity: 15, description: `Test/source ratio is ${profiles.testing.testToSourceRatio}` });
        riskScore += 15;
    }
    if (profiles.dependency.dependencyRisk > 70) {
        riskFactors.push({ factor: 'High dependency count', severity: 20, description: `${profiles.dependency.dependencyCount} dependencies` });
        riskScore += 20;
    }
    else if (profiles.dependency.dependencyRisk > 40) {
        riskFactors.push({ factor: 'Moderate dependency count', severity: 10, description: `${profiles.dependency.dependencyCount} dependencies` });
        riskScore += 10;
    }
    if (profiles.maturity.hasTesting === false && profiles.testing.testFileCount === 0) {
        riskFactors.push({ factor: 'No testing framework', severity: 15, description: 'No testing framework detected' });
        riskScore += 15;
    }
    if (!profiles.maturity.hasCI) {
        riskFactors.push({ factor: 'No CI/CD', severity: 15, description: 'No CI/CD configuration found' });
        riskScore += 15;
    }
    if (!profiles.maturity.hasLinting) {
        riskFactors.push({ factor: 'No linting', severity: 10, description: 'No linting configuration found' });
        riskScore += 10;
    }
    const largeFiles = files.filter(f => f.lines > 500 && !f.isTest);
    if (largeFiles.length > 0) {
        const severity = Math.min(largeFiles.length * 5, 20);
        riskFactors.push({ factor: 'Large files', severity, description: `${largeFiles.length} files exceed 500 lines` });
        riskScore += severity;
    }
    riskScore = Math.min(riskScore, 100);
    const riskLevel = riskScore <= 20 ? 'low' : riskScore <= 50 ? 'medium' : riskScore <= 75 ? 'high' : 'critical';
    return { riskScore, riskFactors, riskLevel };
}
// ─── SYSTEM 8: MATURITY DNA ───────────────────────────
const CI_FILES = ['.github/workflows', '.circleci/config.yml', '.circleci/config.yaml', 'Jenkinsfile', '.gitlab-ci.yml', '.gitlab-ci.yaml', 'azure-pipelines.yml', 'bitbucket-pipelines.yml', 'buildspec.yml', '.travis.yml'];
const LINT_FILES = ['.eslintrc', '.eslintrc.js', '.eslintrc.json', '.eslintrc.yaml', '.eslintrc.yml', 'eslint.config.js', '.pylintrc', '.rubocop.yml', '.golangci.yml', '.golangci.yaml', 'go vet', 'tsconfig.json'];
const FORMAT_FILES = ['.prettierrc', '.prettierrc.js', '.prettierrc.json', '.prettierrc.yaml', '.editorconfig', '.rustfmt.toml', 'black', 'isort'];
const DOC_FILES = ['README.md', 'CONTRIBUTING.md', 'CHANGELOG.md', 'LICENSE', 'docs/', 'documentation/'];
const CONVENTION_DIRS = ['.husky', 'commitlint', '.commitlintrc.json', '.lintstagedrc'];
function buildMaturityProfile(files, rootDir) {
    const paths = new Set(files.map(f => f.relativePath.replace(/\\/g, '/')));
    const allContent = files.map(f => f.relativePath).join(' ').toLowerCase();
    const CD_FILES = ['.github/workflows/cd.yml', '.github/workflows/deploy', 'Jenkinsfile', 'Dockerfile', 'docker-compose.yml', 'k8s/', 'deploy/', 'helm/'];
    const hasCI = CI_FILES.some(cf => paths.has(cf) || [...paths].some(p => p.startsWith(cf)));
    const hasCD = CD_FILES.some(cf => paths.has(cf) || [...paths].some(p => p.startsWith(cf)));
    const hasLinting = LINT_FILES.some(lf => paths.has(lf) || allContent.includes(lf.toLowerCase()));
    const hasFormatting = FORMAT_FILES.some(ff => paths.has(ff));
    const hasDocumentation = DOC_FILES.some(df => paths.has(df) || [...paths].some(p => p.startsWith(df)));
    const hasConventions = CONVENTION_DIRS.some(cd => paths.has(cd) || allContent.includes(cd));
    const hasTesting = files.some(f => f.isTest);
    let score = 0;
    if (hasCI)
        score += 20;
    if (hasCD)
        score += 10;
    if (hasLinting)
        score += 15;
    if (hasFormatting)
        score += 10;
    if (hasDocumentation)
        score += 15;
    if (hasConventions)
        score += 10;
    if (hasTesting)
        score += 20;
    score = Math.min(score, 100);
    const level = score <= 30 ? 'startup' : score <= 55 ? 'growing' : score <= 80 ? 'mature' : 'enterprise';
    const details = [];
    if (hasCI)
        details.push('CI/CD configured');
    if (hasLinting)
        details.push('Linting configured');
    if (hasFormatting)
        details.push('Formatting configured');
    if (hasDocumentation)
        details.push('Documentation present');
    if (hasConventions)
        details.push('Conventions/commit hooks');
    if (hasTesting)
        details.push('Tests present');
    if (!hasCI)
        details.push('Missing CI/CD');
    if (!hasTesting)
        details.push('Missing tests');
    return { level, score, hasCI, hasCD, hasLinting, hasFormatting, hasDocumentation, hasConventions, hasTesting, details };
}
// ─── SYSTEM 9: DEVELOPMENT DNA ────────────────────────
function buildDevelopmentProfile(patterns, outcomes) {
    const totalPatterns = patterns.length;
    let successRate = 0;
    let failureRate = 0;
    let acceptanceRate = 0;
    if (outcomes.size > 0) {
        let totalSuccess = 0;
        let totalFailure = 0;
        let totalAccept = 0;
        let totalReject = 0;
        let count = 0;
        for (const outcome of outcomes.values()) {
            totalSuccess += outcome.successCount || 0;
            totalFailure += outcome.failureCount || 0;
            totalAccept += outcome.acceptanceCount || 0;
            totalReject += outcome.rejectionCount || 0;
            count++;
        }
        const total = totalSuccess + totalFailure;
        successRate = total > 0 ? totalSuccess / total : 0;
        failureRate = total > 0 ? totalFailure / total : 0;
        const totalAcceptReject = totalAccept + totalReject;
        acceptanceRate = totalAcceptReject > 0 ? totalAccept / totalAcceptReject : 0;
    }
    else if (patterns.length > 0) {
        let good = 0;
        let bad = 0;
        for (const p of patterns) {
            if (p.signals) {
                good += p.signals.positive || 0;
                bad += p.signals.negative || 0;
            }
        }
        const total = good + bad;
        successRate = total > 0 ? good / total : 0.5;
        failureRate = total > 0 ? bad / total : 0.5;
        acceptanceRate = 0.5;
    }
    let style;
    let styleConfidence;
    if (successRate >= 0.8 && failureRate <= 0.1) {
        style = 'quality-driven';
        styleConfidence = 0.8;
    }
    else if (acceptanceRate >= 0.7 && successRate >= 0.6) {
        style = 'stability-driven';
        styleConfidence = 0.7;
    }
    else if (successRate < 0.5 || failureRate >= 0.3) {
        style = 'experiment-driven';
        styleConfidence = 0.75;
    }
    else {
        style = 'speed-driven';
        styleConfidence = 0.65;
    }
    const iterationSpeed = failureRate > 0.3 ? 'very-fast' : failureRate > 0.15 ? 'fast' : successRate > 0.8 ? 'slow' : 'moderate';
    return { style, styleConfidence, patternsUsed: totalPatterns, successRate, failureRate, acceptanceRate, iterationSpeed };
}
// ─── SYSTEM 10: PROJECT FINGERPRINT ───────────────────
function buildFingerprint(language, framework, architecture, testing, dependency, complexity, risk, maturity, development) {
    return {
        primaryLanguage: language.primaryLanguage,
        framework: framework.primaryFramework,
        architecture: architecture.architecture,
        complexity: complexity.complexity,
        risk: risk.riskScore,
        maturity: maturity.level,
        testing: testing.maturity,
        developmentStyle: development.style,
    };
}
// ─── DNA BUILD ─────────────────────────────────────────
function buildProjectDNA(projectId, projectPath, options) {
    const files = scanFiles(projectPath);
    const skipSystems = new Set(options?.skipSystems || []);
    const language = skipSystems.has('language') ? buildEmptyLanguage() : buildLanguageProfile(files);
    const framework = skipSystems.has('framework') ? { frameworks: [], primaryFramework: null } : buildFrameworkProfile(files, projectPath);
    const architecture = skipSystems.has('architecture') ? buildEmptyArchitecture() : buildArchitectureProfile(files, projectPath);
    const testing = skipSystems.has('testing') ? buildEmptyTesting() : buildTestingProfile(files, projectPath);
    const dependency = skipSystems.has('dependency') ? buildEmptyDependency() : buildDependencyProfile(files, projectPath);
    const complexity = skipSystems.has('complexity') ? buildEmptyComplexity() : buildComplexityProfile(files, projectPath);
    const maturity = skipSystems.has('maturity') ? buildEmptyMaturity() : buildMaturityProfile(files, projectPath);
    const risk = skipSystems.has('risk') ? buildEmptyRisk() : buildRiskProfile(files, projectPath, { testing, dependency, maturity });
    const development = skipSystems.has('development') ? buildEmptyDevelopment() : buildDevelopmentProfile(options?.patterns || [], options?.outcomes || new Map());
    const fingerprint = buildFingerprint(language, framework, architecture, testing, dependency, complexity, risk, maturity, development);
    const dna = {
        projectId, projectPath, language, framework, architecture, testing, dependency,
        complexity, risk, maturity, development, fingerprint, builtAt: Date.now(), version: 1,
    };
    saveDNA(dna);
    return dna;
}
function buildEmptyLanguage() {
    return { primaryLanguage: 'unknown', languages: [], languagePurity: 0 };
}
function buildEmptyArchitecture() {
    return { architecture: 'unknown', confidence: 0, candidates: [], hasApiLayer: false, hasServiceLayer: false, hasDataLayer: false };
}
function buildEmptyTesting() {
    return { frameworks: [], testFileCount: 0, sourceFileCount: 0, testToSourceRatio: 0, coverageScore: 0, cultureScore: 0, maturity: 'none' };
}
function buildEmptyDependency() {
    return { totalDependencies: 0, totalDevDependencies: 0, dependencyCount: 0, dependencyComplexity: 'low', dependencyRisk: 0, hasPackageManager: false, packageManager: null };
}
function buildEmptyComplexity() {
    return { totalFiles: 0, totalLines: 0, averageFileSize: 0, largestFiles: [], complexity: 'low' };
}
function buildEmptyRisk() {
    return { riskScore: 0, riskFactors: [], riskLevel: 'low' };
}
function buildEmptyMaturity() {
    return { level: 'startup', score: 0, hasCI: false, hasCD: false, hasLinting: false, hasFormatting: false, hasDocumentation: false, hasConventions: false, hasTesting: false, details: [] };
}
function buildEmptyDevelopment() {
    return { style: 'stability-driven', styleConfidence: 0, patternsUsed: 0, successRate: 0, failureRate: 0, acceptanceRate: 0, iterationSpeed: 'moderate' };
}
// ─── STORE ──────────────────────────────────────────────
function loadStore() {
    ensureStoreDir();
    try {
        if (fs.existsSync(DNA_STORE_PATH)) {
            return JSON.parse(fs.readFileSync(DNA_STORE_PATH, 'utf-8'));
        }
    }
    catch { }
    return { projects: {} };
}
function saveStore(data) {
    ensureStoreDir();
    fs.writeFileSync(DNA_STORE_PATH, JSON.stringify(data, null, 2), 'utf-8');
}
function saveDNA(dna) {
    const store = loadStore();
    const existing = store.projects[dna.projectId];
    if (existing)
        dna.version = existing.version + 1;
    dna.builtAt = Date.now();
    store.projects[dna.projectId] = dna;
    saveStore(store);
}
function getDNA(projectId) {
    const store = loadStore();
    return store.projects[projectId] || null;
}
function listDNA() {
    const store = loadStore();
    return Object.values(store.projects);
}
function deleteDNA(projectId) {
    const store = loadStore();
    if (store.projects[projectId]) {
        delete store.projects[projectId];
        saveStore(store);
        return true;
    }
    return false;
}
function getDNAHistory(projectId) {
    return listDNA().filter(d => d.projectId === projectId).sort((a, b) => a.builtAt - b.builtAt);
}
// ─── COMPARISON ─────────────────────────────────────────
function compareDNA(projectA, projectB) {
    const dnaA = getDNA(projectA);
    const dnaB = getDNA(projectB);
    if (!dnaA || !dnaB) {
        return {
            projectA, projectB, overallSimilarity: 0, languageSimilarity: 0, frameworkSimilarity: 0,
            architectureDifference: 'Unknown', riskDifference: 0, complexityDifference: 'Unknown',
            maturityDifference: 'Unknown', testingDifference: 'Unknown', details: ['One or both projects not found'],
        };
    }
    const allLangs = new Set([...dnaA.language.languages.map(l => l.language), ...dnaB.language.languages.map(l => l.language)]);
    const sharedLangs = dnaA.language.languages.filter(a => dnaB.language.languages.some(b => b.language === a.language)).length;
    const languageSimilarity = allLangs.size > 0 ? Math.round((sharedLangs / allLangs.size) * 100) : 0;
    const allFrameworks = new Set([...dnaA.framework.frameworks.map(f => f.name), ...dnaB.framework.frameworks.map(f => f.name)]);
    const sharedFrameworks = dnaA.framework.frameworks.filter(a => dnaB.framework.frameworks.some(b => b.name === a.name)).length;
    const frameworkSimilarity = allFrameworks.size > 0 ? Math.round((sharedFrameworks / allFrameworks.size) * 100) : dnaA.framework.primaryFramework === null && dnaB.framework.primaryFramework === null ? 100 : 0;
    const architectureDifference = dnaA.architecture.architecture === dnaB.architecture.architecture ? 'Same' : `${dnaA.architecture.architecture} vs ${dnaB.architecture.architecture}`;
    const riskDifference = Math.abs(dnaA.risk.riskScore - dnaB.risk.riskScore);
    const complexityDifference = dnaA.complexity.complexity === dnaB.complexity.complexity ? 'Same' : `${dnaA.complexity.complexity} vs ${dnaB.complexity.complexity}`;
    const maturityDifference = dnaA.maturity.level === dnaB.maturity.level ? 'Same' : `${dnaA.maturity.level} vs ${dnaB.maturity.level}`;
    const testingDifference = dnaA.testing.maturity === dnaB.testing.maturity ? 'Same' : `${dnaA.testing.maturity} vs ${dnaB.testing.maturity}`;
    const details = [];
    if (dnaA.language.primaryLanguage !== dnaB.language.primaryLanguage)
        details.push(`Primary language differs: ${dnaA.language.primaryLanguage} vs ${dnaB.language.primaryLanguage}`);
    if (dnaA.framework.primaryFramework !== dnaB.framework.primaryFramework)
        details.push(`Framework differs: ${dnaA.framework.primaryFramework || 'none'} vs ${dnaB.framework.primaryFramework || 'none'}`);
    if (dnaA.architecture.architecture !== dnaB.architecture.architecture)
        details.push(`Architecture differs: ${dnaA.architecture.architecture} vs ${dnaB.architecture.architecture}`);
    details.push(`Risk: ${dnaA.risk.riskScore} vs ${dnaB.risk.riskScore}`);
    details.push(`Maturity: ${dnaA.maturity.level} vs ${dnaB.maturity.level}`);
    details.push(`Complexity: ${dnaA.complexity.complexity} vs ${dnaB.complexity.complexity}`);
    const overallSimilarity = Math.round((languageSimilarity + frameworkSimilarity) / 2);
    return {
        projectA, projectB, overallSimilarity, languageSimilarity, frameworkSimilarity,
        architectureDifference, riskDifference, complexityDifference, maturityDifference, testingDifference, details,
    };
}
//# sourceMappingURL=project-dna.js.map