// tools/reverse-engineer/handler.ts — MCP tool handler for reverse_engineer
import { readFile, stat } from 'node:fs/promises';
import { join, extname, basename, relative } from 'node:path';
import { glob } from 'glob';
import { specStore, knowledgeStore } from '../../storage/index.js';
import { ti } from '../../i18n/index.js';
import { inferDifficulty } from '../../engine/estimator.js';
import { CODE_EXTENSIONS, detectLanguageFromExtension, getFrameworkTerminology, detectTechDebt, IGNORE_PATTERNS, } from './analyzer.js';
export async function handleReverseEngineer(args) {
    const { path: targetPath, projectId, depth = 'shallow' } = args;
    // 1. Validate path exists
    try {
        await stat(targetPath);
    }
    catch {
        return {
            content: [
                { type: 'text', text: ti('reverseEngineer.pathNotFound', { path: targetPath }) },
            ],
            isError: true,
        };
    }
    // 2. Load project knowledge for context
    const knowledge = await knowledgeStore.getKnowledge(projectId);
    const projectPath = knowledge?.projectPath ?? targetPath;
    // 3. Scan code files
    const fileStat = await stat(targetPath);
    const isDir = fileStat.isDirectory();
    let files;
    if (isDir) {
        const maxDepthValue = depth === 'deep' ? 10 : 4;
        const found = await glob('**/*', {
            cwd: targetPath,
            nodir: true,
            ignore: IGNORE_PATTERNS,
            maxDepth: maxDepthValue,
        });
        files = found.filter((f) => CODE_EXTENSIONS.has(extname(f)));
        if (files.length > 200 && depth === 'shallow') {
            return {
                content: [
                    {
                        type: 'text',
                        text: ti('reverseEngineer.tooLarge', { count: String(files.length) }),
                    },
                ],
                isError: true,
            };
        }
    }
    else {
        files = [basename(targetPath)];
    }
    // 4. Analyze code structure
    const interfaces = [];
    const dependencies = [];
    const layers = [];
    const exports = [];
    const patterns = [];
    let totalLines = 0;
    const limit = depth === 'deep' ? files.length : Math.min(files.length, 100);
    for (let i = 0; i < limit; i++) {
        const file = files[i];
        /* v8 ignore next 3 */
        if (!file) {
            continue;
        }
        const fullPath = isDir ? join(targetPath, file) : targetPath;
        try {
            const content = await readFile(fullPath, 'utf-8');
            const lines = content.split('\n');
            totalLines += lines.length;
            // Extract interfaces and types
            const ifaceMatches = content.matchAll(/(?:interface|type|class|struct|trait|protocol)\s+(\w+)/g);
            for (const match of ifaceMatches) {
                if (match[1] && !interfaces.includes(match[1])) {
                    interfaces.push(match[1]);
                }
            }
            // Extract exported functions/components
            const exportMatches = content.matchAll(/export\s+(?:default\s+)?(?:async\s+)?(?:function|const|class)\s+(\w+)/g);
            for (const match of exportMatches) {
                if (match[1] && !exports.includes(match[1])) {
                    exports.push(match[1]);
                }
            }
            // Extract dependencies (imports)
            const importMatches = content.matchAll(/(?:import|from)\s+['"]([^'"]+)['"]/g);
            for (const match of importMatches) {
                if (match[1] && !match[1].startsWith('.') && !dependencies.includes(match[1])) {
                    dependencies.push(match[1]);
                }
            }
            // Infer layers from file paths
            const relPath = isDir ? file : relative(projectPath, targetPath);
            if (/(?:component|page|view|screen|ui)\//i.exec(relPath) &&
                !layers.includes('presentation')) {
                layers.push('presentation');
            }
            if (/(?:service|handler|use-case)\//i.exec(relPath) && !layers.includes('application')) {
                layers.push('application');
            }
            if (/(?:model|entity|domain|core)\//i.exec(relPath) && !layers.includes('domain')) {
                layers.push('domain');
            }
            if (/(?:repository|adapter|infra|db|api)\//i.exec(relPath) &&
                !layers.includes('infrastructure')) {
                layers.push('infrastructure');
            }
            // Detect patterns
            if (content.includes('useState') || content.includes('useEffect')) {
                if (!patterns.includes('React hooks')) {
                    patterns.push('React hooks');
                }
            }
            if (/(?:Repository|Service|Controller|Handler)\s/.exec(content)) {
                if (!patterns.includes('layered-architecture')) {
                    patterns.push('layered-architecture');
                }
            }
            if (/async\s+function|await\s/.exec(content)) {
                if (!patterns.includes('async/await')) {
                    patterns.push('async/await');
                }
            }
        }
        catch {
            // Skip unreadable files
        }
    }
    // 4b. Detect tech debt indicators (SPEC-010)
    const techDebt = detectTechDebt(files, totalLines, patterns);
    // 4c. SPEC-027: detect dominant language and framework terminology
    const languageCounts = new Map();
    for (const file of files) {
        const lang = detectLanguageFromExtension(extname(file));
        if (lang !== 'unknown') {
            languageCounts.set(lang, (languageCounts.get(lang) ?? 0) + 1);
        }
    }
    const dominantLanguage = Array.from(languageCounts.entries()).reduce((max, entry) => (entry[1] > max[1] ? entry : max), ['unknown', 0])[0];
    const frameworkTerminology = getFrameworkTerminology(dominantLanguage, dependencies);
    // 5. Infer spec metadata
    const dirName = isDir ? basename(targetPath) : basename(targetPath, extname(targetPath));
    const scope = files.length > 20 ? 'cross-module' : files.length > 5 ? 'feature' : 'trivial';
    const specType = patterns.includes('layered-architecture') ? 'refactor' : 'feature';
    const difficulty = inferDifficulty(specType, scope);
    // 6. Build spec
    const specId = `SPEC-RE-${Date.now().toString(36).toUpperCase()}`;
    const slug = dirName.toLowerCase().replace(/[^a-z0-9]+/g, '-');
    const now = new Date().toISOString();
    const spec = {
        id: specId,
        title: `[Reverse-engineered] ${dirName}`,
        slug,
        type: specType,
        scope,
        status: 'draft',
        difficulty,
        risk: scope === 'cross-module' ? 'medium' : 'low',
        projectId,
        createdAt: now,
        updatedAt: now,
        specPath: '',
        technicalPath: '',
        estimation: {
            devHours: 0,
            reviewHours: 0,
            recommendedModel: 'sonnet',
            tokensOpus: 0,
            tokensSonnet: 0,
            apiCostUsd: 0,
            hourlyRate: 0,
            humanCostUsd: 0,
            totalCostUsd: 0,
            tokenOptimization: { mode: 'local', reasoning: '', estimatedTokens: 0, savings: '' },
        },
        actuals: null,
        target: layers.includes('presentation')
            ? 'frontend'
            : layers.includes('infrastructure')
                ? 'backend'
                : 'shared',
        tags: [...patterns],
        dependencies: [],
        blockedBy: [],
        gitBranch: '',
        impactAnalysis: {
            affectedModules: layers,
            affectedFiles: files.slice(0, 50),
            breakingChanges: false,
            requiresMigration: false,
            migrationReversible: true,
            requiresFeatureFlag: false,
            rollbackPlan: '',
            testingStrategy: { unitTests: [], integrationTests: [], e2eTests: [], manualTests: [] },
            environments: ['development'],
        },
    };
    // 7. Save spec
    await specStore.createSpec(projectId, spec);
    // 8. Build output
    const analysis = {
        filesAnalyzed: limit,
        totalLines,
        interfacesDetected: interfaces.slice(0, 30),
        exportsDetected: exports.slice(0, 30),
        dependenciesFound: dependencies.slice(0, 30),
        layersIdentified: layers,
        patternsDetected: patterns,
        inferredScope: scope,
        inferredType: specType,
        inferredDifficulty: difficulty,
        techDebt,
        // SPEC-027: language-specific analysis strategy
        dominantLanguage,
        frameworkTerminology,
        specStatus: 'draft',
        requiresHumanReview: true,
    };
    return {
        content: [
            {
                type: 'text',
                text: ti('reverseEngineer.completed', { count: String(limit) }),
            },
            {
                type: 'text',
                text: JSON.stringify({
                    specId,
                    title: spec.title,
                    status: 'draft',
                    analysis,
                }, null, 2),
            },
        ],
    };
}
//# sourceMappingURL=handler.js.map