"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.aggregateProfile = aggregateProfile;
exports.scanFullPC = scanFullPC;
exports.getFullScanResult = getFullScanResult;
exports.formatFullScanReport = formatFullScanReport;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const os = __importStar(require("os"));
const database_1 = require("../../06-memory/database/database");
// ─── Project Discovery ──────────────────────────────────────────────────────
const PROJECT_MARKERS = [
    'package.json', 'requirements.txt', 'pyproject.toml', 'setup.py',
    'go.mod', 'Cargo.toml', 'pom.xml', 'build.gradle',
    'Gemfile', 'composer.json', 'pubspec.yaml', 'mix.exs',
    'Makefile', 'CMakeLists.txt',
];
const SCAN_DIRS = [
    os.homedir(),
    path.join(os.homedir(), 'Documents'),
    path.join(os.homedir(), 'Desktop'),
    path.join(os.homedir(), 'Projects'),
    path.join(os.homedir(), 'Code'),
    path.join(os.homedir(), 'dev'),
    path.join(os.homedir(), 'work'),
    path.join(os.homedir(), 'repos'),
    path.join(os.homedir(), 'src'),
];
const SKIP_DIRS = new Set([
    'node_modules', '.git', 'dist', 'build', '.next', '.nuxt',
    'coverage', '.cache', '__pycache__', '.pytest_cache',
    'vendor', '.gradle', 'target', '.tox', 'venv', '.venv',
    '.fivo', '.idea', '.vscode', 'AppData', 'Applications',
    'Windows', 'Program Files', 'Program Files (x86)',
    '.android', '.gradle', '.m2', '.cargo',
]);
const MAX_DEPTH = 4;
const MAX_PROJECTS = 100;
const CODE_EXTS = new Set([
    '.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs',
    '.py', '.go', '.rs', '.java', '.cs', '.cpp', '.c', '.h',
    '.rb', '.php', '.swift', '.kt', '.scala',
    '.sql', '.sh', '.bash', '.zsh',
    '.yaml', '.yml', '.json', '.toml',
    '.html', '.css', '.scss', '.less',
    '.vue', '.svelte',
]);
function findProjects(dir, depth = 0, found = []) {
    if (depth > MAX_DEPTH || found.length >= MAX_PROJECTS)
        return found;
    if (!fs.existsSync(dir))
        return found;
    try {
        const entries = fs.readdirSync(dir, { withFileTypes: true });
        for (const entry of entries) {
            if (found.length >= MAX_PROJECTS)
                break;
            if (SKIP_DIRS.has(entry.name))
                continue;
            if (entry.name.startsWith('.') && entry.name !== '.env.example')
                continue;
            const fullPath = path.join(dir, entry.name);
            if (entry.isDirectory()) {
                // Check if this directory is a project
                const isProject = PROJECT_MARKERS.some(m => fs.existsSync(path.join(fullPath, m)));
                if (isProject) {
                    found.push(fullPath);
                }
                // Recurse deeper
                findProjects(fullPath, depth + 1, found);
            }
        }
    }
    catch { /* skip inaccessible dirs */ }
    return found;
}
function analyzeProject(projectPath) {
    const name = path.basename(projectPath);
    const languages = {};
    let fileCount = 0;
    let lineCount = 0;
    // Check for project markers
    const hasPackageJson = fs.existsSync(path.join(projectPath, 'package.json'));
    const hasRequirements = fs.existsSync(path.join(projectPath, 'requirements.txt')) ||
        fs.existsSync(path.join(projectPath, 'pyproject.toml'));
    const hasGoMod = fs.existsSync(path.join(projectPath, 'go.mod'));
    const hasCargoToml = fs.existsSync(path.join(projectPath, 'Cargo.toml'));
    const hasPomXml = fs.existsSync(path.join(projectPath, 'pom.xml'));
    // Walk source files
    const walk = (dir, depth = 0) => {
        if (depth > 3)
            return;
        try {
            const entries = fs.readdirSync(dir, { withFileTypes: true });
            for (const entry of entries) {
                if (SKIP_DIRS.has(entry.name))
                    continue;
                if (entry.name.startsWith('.'))
                    continue;
                const fullPath = path.join(dir, entry.name);
                if (entry.isDirectory()) {
                    walk(fullPath, depth + 1);
                }
                else if (entry.isFile()) {
                    const ext = path.extname(entry.name).toLowerCase();
                    if (CODE_EXTS.has(ext)) {
                        fileCount++;
                        const lang = getLang(ext);
                        languages[lang] = (languages[lang] || 0) + 1;
                        try {
                            const content = fs.readFileSync(fullPath, 'utf-8');
                            lineCount += content.split('\n').length;
                        }
                        catch { }
                    }
                }
            }
        }
        catch { }
    };
    walk(projectPath);
    return {
        name,
        path: projectPath,
        languages,
        fileCount,
        lineCount,
        hasPackageJson,
        hasRequirements,
        hasGoMod,
        hasCargoToml,
        hasPomXml,
    };
}
function getLang(ext) {
    const map = {
        '.ts': 'typescript', '.tsx': 'typescript',
        '.js': 'javascript', '.jsx': 'javascript', '.mjs': 'javascript', '.cjs': 'javascript',
        '.py': 'python', '.go': 'go', '.rs': 'rust',
        '.java': 'java', '.cs': 'csharp', '.cpp': 'cpp', '.c': 'c', '.h': 'c',
        '.rb': 'ruby', '.php': 'php', '.swift': 'swift', '.kt': 'kotlin',
        '.sql': 'sql', '.sh': 'shell', '.bash': 'shell',
        '.html': 'html', '.css': 'css', '.scss': 'scss',
        '.vue': 'vue', '.svelte': 'svelte',
        '.yaml': 'yaml', '.yml': 'yaml', '.json': 'json', '.toml': 'toml',
    };
    return map[ext] || 'other';
}
// ─── Aggregation ─────────────────────────────────────────────────────────────
function aggregateProfile(projects) {
    const allLanguages = {};
    let totalFiles = 0;
    for (const p of projects) {
        for (const [lang, count] of Object.entries(p.languages)) {
            allLanguages[lang] = (allLanguages[lang] || 0) + count;
        }
        totalFiles += p.fileCount;
    }
    // Primary language
    const langEntries = Object.entries(allLanguages).sort((a, b) => b[1] - a[1]);
    const primaryLanguage = langEntries.length > 0 ? langEntries[0][0] : 'unknown';
    // Language breakdown
    const languages = langEntries.map(([name, files]) => ({
        name,
        files,
        percent: totalFiles > 0 ? Math.round((files / totalFiles) * 100) : 0,
    }));
    // Detect frameworks
    const frameworks = [];
    const hasReact = projects.some(p => p.hasPackageJson && fs.existsSync(path.join(p.path, 'package.json')) &&
        fs.readFileSync(path.join(p.path, 'package.json'), 'utf-8').includes('react'));
    const hasNext = projects.some(p => p.hasPackageJson && fs.existsSync(path.join(p.path, 'package.json')) &&
        fs.readFileSync(path.join(p.path, 'package.json'), 'utf-8').includes('next'));
    const hasDjango = projects.some(p => p.hasRequirements && fs.existsSync(path.join(p.path, 'requirements.txt')) &&
        fs.readFileSync(path.join(p.path, 'requirements.txt'), 'utf-8').includes('django'));
    const hasFastAPI = projects.some(p => p.hasRequirements && fs.existsSync(path.join(p.path, 'requirements.txt')) &&
        fs.readFileSync(path.join(p.path, 'requirements.txt'), 'utf-8').includes('fastapi'));
    if (hasReact)
        frameworks.push('React');
    if (hasNext)
        frameworks.push('Next.js');
    if (hasDjango)
        frameworks.push('Django');
    if (hasFastAPI)
        frameworks.push('FastAPI');
    // Scan code patterns across all projects
    const styleCounts = { single: 0, double: 0, semicolons: 0, noSemicolons: 0, tabs: 0, spaces: 0, camelCase: 0, snake_case: 0, PascalCase: 0, kebabCase: 0 };
    const errorCounts = { tryCatch: 0, optionalChain: 0, nullCheck: 0, none: 0 };
    const funcCounts = { arrow: 0, declaration: 0, async: 0 };
    for (const p of projects) {
        try {
            walkForPatterns(p.path, styleCounts, errorCounts, funcCounts);
        }
        catch { }
    }
    // Determine style
    const namingStyle = styleCounts.camelCase >= styleCounts.snake_case &&
        styleCounts.camelCase >= styleCounts.PascalCase &&
        styleCounts.camelCase >= styleCounts.kebabCase
        ? 'camelCase'
        : styleCounts.snake_case >= styleCounts.PascalCase && styleCounts.snake_case >= styleCounts.kebabCase
            ? 'snake_case'
            : styleCounts.PascalCase >= styleCounts.kebabCase
                ? 'PascalCase'
                : styleCounts.kebabCase > 0
                    ? 'kebab-case'
                    : 'mixed';
    const quoteStyle = styleCounts.single > styleCounts.double ? 'single' : 'double';
    const semicolonStyle = styleCounts.semicolons > styleCounts.noSemicolons ? 'always' : 'never';
    const indentStyle = styleCounts.spaces > styleCounts.tabs ? 'spaces' : 'tabs';
    const functionStyle = funcCounts.arrow > funcCounts.declaration ? 'arrow' : 'declaration';
    const asyncStyle = funcCounts.async > 0 ? 'uses-async' : 'sync-only';
    const errorHandling = errorCounts.tryCatch > 0 ? 'try-catch' :
        errorCounts.optionalChain > 0 ? 'optional-chaining' : 'none';
    const architectureStyle = primaryLanguage === 'typescript' ? 'typed' : primaryLanguage === 'python' ? 'dynamic' : 'mixed';
    const testPattern = projects.some(p => fs.existsSync(path.join(p.path, 'jest.config.js')) ||
        fs.existsSync(path.join(p.path, 'jest.config.ts')) || fs.existsSync(path.join(p.path, 'vitest.config.ts'))) ? 'jest/vitest' : 'unknown';
    const strengths = [];
    const improvements = [];
    if (asyncStyle === 'uses-async')
        strengths.push('Uses async/await across projects');
    if (errorHandling !== 'none')
        strengths.push('Uses error handling patterns');
    else
        improvements.push('Add error handling across projects');
    if (testPattern !== 'unknown')
        strengths.push('Has testing setup');
    else
        improvements.push('Add testing to more projects');
    if (languages.length > 2)
        strengths.push('Polyglot developer');
    if (frameworks.length > 0)
        strengths.push(`Uses ${frameworks.join(', ')}`);
    return {
        primaryLanguage,
        languages,
        frameworks,
        namingStyle,
        quoteStyle,
        semicolonStyle,
        indentStyle,
        functionStyle,
        asyncStyle,
        errorHandling,
        architectureStyle,
        testPattern,
        strengths,
        improvements,
        totalPatterns: styleCounts.single + styleCounts.double + errorCounts.tryCatch + funcCounts.arrow,
    };
}
function walkForPatterns(dir, style, errors, funcs, depth = 0) {
    if (depth > 3)
        return;
    try {
        const entries = fs.readdirSync(dir, { withFileTypes: true });
        for (const entry of entries) {
            if (SKIP_DIRS.has(entry.name) || entry.name.startsWith('.'))
                continue;
            const fullPath = path.join(dir, entry.name);
            if (entry.isDirectory()) {
                walkForPatterns(fullPath, style, errors, funcs, depth + 1);
            }
            else if (entry.isFile()) {
                const ext = path.extname(entry.name).toLowerCase();
                if (CODE_EXTS.has(ext) && ext !== '.json' && ext !== '.yaml' && ext !== '.yml' && ext !== '.toml') {
                    try {
                        const content = fs.readFileSync(fullPath, 'utf-8');
                        const lines = content.split('\n');
                        for (const line of lines) {
                            const t = line.trim();
                            if (t.length === 0 || t.startsWith('//') || t.startsWith('#'))
                                continue;
                            // Quotes
                            const sq = (t.match(/'/g) || []).length;
                            const dq = (t.match(/"/g) || []).length;
                            if (sq > dq)
                                style.single++;
                            else if (dq > sq)
                                style.double++;
                            // Semicolons — only count lines that look like statements (not pure braces/closers)
                            if (/^[}\])]/.test(t) || t.length === 0) {
                                // skip — not a statement line
                            }
                            else if (t.endsWith(';'))
                                style.semicolons++;
                            else if (t.length > 0 && /[a-zA-Z0-9"'`]/.test(t))
                                style.noSemicolons++;
                            // Indent
                            if (/^\t/.test(line))
                                style.tabs++;
                            else if (/^  \S/.test(line))
                                style.spaces++;
                        }
                        // Error handling
                        errors.tryCatch += (content.match(/\btry\s*\{/g) || []).length;
                        errors.optionalChain += (content.match(/\?\./g) || []).length;
                        errors.nullCheck += (content.match(/===?\s*null|!==?\s*null/g) || []).length;
                        // Naming style — count identifiers in declarations
                        const camelMatches = content.match(/\b(?:const|let|var|function)\s+([a-z][a-zA-Z0-9]*)\b/g) || [];
                        const snakeMatches = content.match(/\b(?:const|let|var|function)\s+([a-z][a-z0-9_]*)\b/g) || [];
                        const pascalMatches = content.match(/\b(?:class|interface|type|function)\s+([A-Z][a-zA-Z0-9]*)\b/g) || [];
                        const kebabMatches = content.match(/['"`]([a-z][a-z0-9]*-[a-z0-9-]+)['"`]/g) || [];
                        style.camelCase += camelMatches.length;
                        style.snake_case += snakeMatches.length;
                        style.PascalCase += pascalMatches.length;
                        style.kebabCase += kebabMatches.length;
                        // Functions
                        funcs.arrow += (content.match(/(?:const|let)\s+\w+\s*=\s*(?:\([^)]*\)|\w+)\s*=>/g) || []).length;
                        funcs.declaration += (content.match(/\bfunction\s+\w+/g) || []).length;
                        funcs.async += (content.match(/\basync\s+(?:function|\()/g) || []).length;
                    }
                    catch { }
                }
            }
        }
    }
    catch { }
}
// ─── Database Storage ────────────────────────────────────────────────────────
function saveFullScan(result) {
    const db = (0, database_1.getDb)();
    db.exec(`
    CREATE TABLE IF NOT EXISTS full_scans (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      scanned_at TEXT DEFAULT (datetime('now')),
      total_projects INTEGER,
      total_files INTEGER,
      total_lines INTEGER,
      all_languages TEXT,
      aggregated_profile TEXT,
      projects_json TEXT
    )
  `);
    db.prepare('DELETE FROM full_scans').run();
    db.prepare('INSERT INTO full_scans (total_projects, total_files, total_lines, all_languages, aggregated_profile, projects_json) VALUES (?, ?, ?, ?, ?, ?)')
        .run(result.totalProjects, result.totalFiles, result.totalLines, JSON.stringify(result.allLanguages), JSON.stringify(result.aggregatedProfile), JSON.stringify(result.projects.map(p => ({ name: p.name, path: p.path, files: p.fileCount, lines: p.lineCount, languages: p.languages }))));
}
// ─── Public API ──────────────────────────────────────────────────────────────
function scanFullPC() {
    console.log('  Discovering projects...');
    const allProjects = [];
    for (const dir of SCAN_DIRS) {
        if (fs.existsSync(dir)) {
            findProjects(dir, 0, allProjects);
        }
    }
    // Also scan from common development locations (cross-platform)
    const extraDirs = [];
    if (process.platform === 'win32') {
        const home = os.homedir();
        extraDirs.push(home);
        for (const drive of ['C', 'D', 'E']) {
            const root = `${drive}:\\`;
            if (fs.existsSync(root))
                extraDirs.push(root);
        }
    }
    else {
        extraDirs.push('/workspace', '/repos', '/var/projects');
    }
    for (const dir of extraDirs) {
        if (fs.existsSync(dir)) {
            findProjects(dir, 0, allProjects);
        }
    }
    // Deduplicate
    const uniqueProjects = [...new Set(allProjects)];
    console.log(`  Found ${uniqueProjects.length} projects. Scanning...`);
    const projects = [];
    const allLanguages = {};
    let totalFiles = 0;
    let totalLines = 0;
    for (let i = 0; i < uniqueProjects.length; i++) {
        const p = uniqueProjects[i];
        console.log(`  [${i + 1}/${uniqueProjects.length}] ${path.basename(p)}`);
        const info = analyzeProject(p);
        projects.push(info);
        for (const [lang, count] of Object.entries(info.languages)) {
            allLanguages[lang] = (allLanguages[lang] || 0) + count;
        }
        totalFiles += info.fileCount;
        totalLines += info.lineCount;
    }
    console.log('  Building profile...');
    const aggregatedProfile = aggregateProfile(projects);
    const result = {
        scannedAt: new Date().toISOString(),
        totalProjects: projects.length,
        totalFiles,
        totalLines,
        allLanguages,
        projects,
        aggregatedProfile,
    };
    saveFullScan(result);
    return result;
}
function getFullScanResult() {
    const db = (0, database_1.getDb)();
    try {
        db.exec(`
      CREATE TABLE IF NOT EXISTS full_scans (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        scanned_at TEXT DEFAULT (datetime('now')),
        total_projects INTEGER,
        total_files INTEGER,
        total_lines INTEGER,
        all_languages TEXT,
        aggregated_profile TEXT,
        projects_json TEXT
      )
    `);
        const row = db.prepare('SELECT * FROM full_scans ORDER BY scanned_at DESC LIMIT 1').get();
        if (!row)
            return null;
        return {
            scannedAt: String(row.scanned_at),
            totalProjects: Number(row.total_projects),
            totalFiles: Number(row.total_files),
            totalLines: Number(row.total_lines),
            allLanguages: JSON.parse(String(row.all_languages)),
            projects: JSON.parse(String(row.projects_json)),
            aggregatedProfile: JSON.parse(String(row.aggregated_profile)),
        };
    }
    catch {
        return null;
    }
}
function formatFullScanReport(result) {
    const lines = [];
    lines.push('');
    lines.push('  CELL — FULL PC SCAN');
    lines.push('  ─────────────────────────────────────');
    lines.push('');
    lines.push(`  Projects: ${result.totalProjects}`);
    lines.push(`  Files:    ${result.totalFiles.toLocaleString()}`);
    lines.push(`  Lines:    ${result.totalLines.toLocaleString()}`);
    lines.push('');
    const p = result.aggregatedProfile;
    lines.push('  YOUR DEVELOPER PROFILE:');
    lines.push('');
    lines.push(`  Primary Language: ${p.primaryLanguage}`);
    lines.push(`  Frameworks: ${p.frameworks.length > 0 ? p.frameworks.join(', ') : 'none detected'}`);
    lines.push('');
    lines.push('  Languages:');
    for (const l of p.languages.slice(0, 8)) {
        const bar = '#'.repeat(Math.max(1, Math.round(l.percent / 5)));
        lines.push(`    ${l.name.padEnd(12)} ${bar} ${l.percent}% (${l.files} files)`);
    }
    lines.push('');
    lines.push('  Style:');
    lines.push(`    Naming:      ${p.namingStyle}`);
    lines.push(`    Quotes:      ${p.quoteStyle}`);
    lines.push(`    Semicolons:  ${p.semicolonStyle}`);
    lines.push(`    Indent:      ${p.indentStyle}`);
    lines.push(`    Functions:   ${p.functionStyle}`);
    lines.push(`    Async:       ${p.asyncStyle}`);
    lines.push(`    Errors:      ${p.errorHandling}`);
    lines.push(`    Architecture:${p.architectureStyle}`);
    lines.push(`    Testing:     ${p.testPattern}`);
    lines.push('');
    if (p.strengths.length > 0) {
        lines.push('  Strengths:');
        for (const s of p.strengths)
            lines.push(`    + ${s}`);
    }
    if (p.improvements.length > 0) {
        lines.push('  Improvements:');
        for (const i of p.improvements)
            lines.push(`    ! ${i}`);
    }
    lines.push('');
    lines.push('  Projects Scanned:');
    for (const proj of result.projects.slice(0, 20)) {
        const langs = Object.entries(proj.languages).sort((a, b) => b[1] - a[1]).slice(0, 3).map(([l]) => l).join(', ');
        lines.push(`    ${proj.name}: ${proj.fileCount} files, ${proj.lineCount.toLocaleString()} lines (${langs})`);
    }
    if (result.projects.length > 20) {
        lines.push(`    ... and ${result.projects.length - 20} more`);
    }
    lines.push('');
    return lines.join('\n');
}
//# sourceMappingURL=pc-scanner.js.map