import { promises as fs } from 'fs';
import path from 'path';
export class CodeMemory {
    configManager;
    codeContextPath;
    codeContexts;
    constructor(configManager) {
        this.configManager = configManager;
        this.codeContextPath = '';
        this.codeContexts = new Map();
    }
    async initialize() {
        const storageManager = this.configManager.getStorageManager();
        const location = await storageManager.getStorageLocation();
        this.codeContextPath = path.join(location.data, 'memory', 'code-contexts.json');
        // Ensure directory exists
        await fs.mkdir(path.dirname(this.codeContextPath), { recursive: true });
        // Load existing code contexts
        await this.loadCodeContexts();
    }
    async analyzeContext(options) {
        const fullPath = path.resolve(options.filePath);
        const contextKey = options.functionName ? `${fullPath}:${options.functionName}` : fullPath;
        // Check if we have cached context
        const cached = this.codeContexts.get(contextKey);
        if (cached) {
            return cached;
        }
        // Analyze the code file
        const context = await this.performCodeAnalysis(options);
        // Cache the context
        this.codeContexts.set(contextKey, context);
        await this.saveCodeContexts();
        return context;
    }
    async updateCodeContext(filePath, context) {
        this.codeContexts.set(filePath, context);
        await this.saveCodeContexts();
    }
    async findRelatedCode(filePath) {
        const targetContext = this.codeContexts.get(filePath);
        if (!targetContext)
            return [];
        const related = [];
        for (const [path, context] of this.codeContexts) {
            if (path === filePath)
                continue;
            let score = 0;
            // Check if files import each other
            const hasImportRelation = context.dependencies.some(dep => dep.filePath === filePath) || targetContext.dependencies.some(dep => dep.filePath === path.replace(/:[^:]*$/, '') // Remove function name if present
            );
            if (hasImportRelation) {
                score += 0.5;
            }
            // Check for similar usage patterns
            const sharedPatterns = targetContext.usagePatterns.filter(pattern => context.usagePatterns.includes(pattern));
            score += sharedPatterns.length * 0.2;
            // Check for related code references
            const relatedCodeMatch = targetContext.relatedCode.some(related => related.file === context.filePath);
            if (relatedCodeMatch) {
                score += 0.3;
            }
            if (score > 0.2) {
                related.push({ context, score });
            }
        }
        return related
            .sort((a, b) => b.score - a.score)
            .slice(0, 5)
            .map(item => item.context);
    }
    async getCodeStats() {
        const contexts = Array.from(this.codeContexts.values());
        const fileTypes = {};
        const patternCounts = {};
        const dependencyGraph = {};
        contexts.forEach(context => {
            const ext = path.extname(context.filePath);
            fileTypes[ext] = (fileTypes[ext] || 0) + 1;
            context.usagePatterns.forEach(pattern => {
                patternCounts[pattern] = (patternCounts[pattern] || 0) + 1;
            });
            const deps = context.dependencies
                .filter(dep => dep.filePath)
                .map(dep => dep.filePath);
            if (deps.length > 0) {
                dependencyGraph[context.filePath] = deps;
            }
        });
        const topPatterns = Object.entries(patternCounts)
            .sort(([, a], [, b]) => b - a)
            .slice(0, 10)
            .map(([pattern, count]) => ({ pattern, count }));
        return {
            totalContexts: contexts.length,
            fileTypes,
            topPatterns,
            dependencyGraph,
        };
    }
    async performCodeAnalysis(options) {
        try {
            const content = await fs.readFile(options.filePath, 'utf-8');
            const ext = path.extname(options.filePath);
            let context;
            switch (ext) {
                case '.ts':
                case '.tsx':
                case '.js':
                case '.jsx':
                    context = await this.analyzeJavaScriptTypeScript(content, options);
                    break;
                case '.py':
                    context = await this.analyzePython(content, options);
                    break;
                default:
                    context = await this.analyzeGeneric(content, options);
            }
            // Add related code if requested
            if (options.includeRelated) {
                context.relatedCode = await this.findRelatedCodeReferences(context, options.depth || 2);
            }
            return context;
        }
        catch (error) {
            // Return minimal context if analysis fails
            return {
                filePath: options.filePath,
                functionName: options.functionName,
                summary: `Failed to analyze: ${error.message}`,
                dependencies: [],
                usagePatterns: [],
                relatedCode: [],
                recommendations: ['File could not be analyzed - check file permissions and format'],
            };
        }
    }
    async analyzeJavaScriptTypeScript(content, options) {
        const lines = content.split('\n');
        const dependencies = [];
        const usagePatterns = [];
        const recommendations = [];
        // Extract imports
        const importRegex = /^import\s+(?:.*\s+from\s+)?['"]([^'"]+)['"];?/gm;
        let match;
        while ((match = importRegex.exec(content)) !== null) {
            dependencies.push({
                name: match[1],
                type: 'import',
                description: `Imported module: ${match[1]}`,
                filePath: this.resolveImportPath(match[1], options.filePath),
            });
        }
        // Extract function/class definitions
        const functionRegex = /^(?:export\s+)?(?:async\s+)?function\s+(\w+)/gm;
        while ((match = functionRegex.exec(content)) !== null) {
            dependencies.push({
                name: match[1],
                type: 'function',
                description: `Function: ${match[1]}`,
            });
        }
        const classRegex = /^(?:export\s+)?class\s+(\w+)/gm;
        while ((match = classRegex.exec(content)) !== null) {
            dependencies.push({
                name: match[1],
                type: 'class',
                description: `Class: ${match[1]}`,
            });
        }
        // Detect usage patterns
        if (content.includes('React'))
            usagePatterns.push('React component');
        if (content.includes('express'))
            usagePatterns.push('Express.js server');
        if (content.includes('async/await'))
            usagePatterns.push('Async/await pattern');
        if (content.includes('jest') || content.includes('describe('))
            usagePatterns.push('Jest testing');
        if (content.includes('useState') || content.includes('useEffect'))
            usagePatterns.push('React hooks');
        if (content.includes('try/catch'))
            usagePatterns.push('Error handling');
        // Generate recommendations
        if (!content.includes('use strict') && content.includes('function')) {
            recommendations.push('Consider using strict mode');
        }
        if (content.includes('any') && options.filePath.endsWith('.ts')) {
            recommendations.push('Avoid using "any" type in TypeScript');
        }
        if (content.includes('console.log')) {
            recommendations.push('Remove console.log statements before production');
        }
        let summary = `${path.basename(options.filePath)} - `;
        if (usagePatterns.length > 0) {
            summary += usagePatterns[0];
        }
        else {
            summary += 'JavaScript/TypeScript file';
        }
        if (options.functionName) {
            const functionMatch = content.match(new RegExp(`function\\s+${options.functionName}\\s*\\(`));
            if (functionMatch) {
                summary += ` (analyzing function: ${options.functionName})`;
            }
        }
        return {
            filePath: options.filePath,
            functionName: options.functionName,
            summary,
            dependencies,
            usagePatterns,
            relatedCode: [],
            recommendations,
        };
    }
    async analyzePython(content, options) {
        const dependencies = [];
        const usagePatterns = [];
        const recommendations = [];
        // Extract imports
        const importRegex = /^(?:from\s+(\S+)\s+)?import\s+(.+)$/gm;
        let match;
        while ((match = importRegex.exec(content)) !== null) {
            const module = match[1] || match[2].split(',')[0].trim();
            dependencies.push({
                name: module,
                type: 'import',
                description: `Imported: ${module}`,
            });
        }
        // Extract function definitions
        const functionRegex = /^def\s+(\w+)\s*\(/gm;
        while ((match = functionRegex.exec(content)) !== null) {
            dependencies.push({
                name: match[1],
                type: 'function',
                description: `Function: ${match[1]}`,
            });
        }
        // Extract class definitions
        const classRegex = /^class\s+(\w+)/gm;
        while ((match = classRegex.exec(content)) !== null) {
            dependencies.push({
                name: match[1],
                type: 'class',
                description: `Class: ${match[1]}`,
            });
        }
        // Detect patterns
        if (content.includes('flask'))
            usagePatterns.push('Flask web application');
        if (content.includes('django'))
            usagePatterns.push('Django web application');
        if (content.includes('pandas'))
            usagePatterns.push('Data analysis with pandas');
        if (content.includes('numpy'))
            usagePatterns.push('Numerical computing');
        if (content.includes('async def'))
            usagePatterns.push('Async/await pattern');
        if (content.includes('unittest') || content.includes('pytest'))
            usagePatterns.push('Unit testing');
        return {
            filePath: options.filePath,
            functionName: options.functionName,
            summary: `${path.basename(options.filePath)} - Python ${usagePatterns[0] || 'script'}`,
            dependencies,
            usagePatterns,
            relatedCode: [],
            recommendations,
        };
    }
    async analyzeGeneric(content, options) {
        const ext = path.extname(options.filePath);
        const dependencies = [];
        const usagePatterns = [];
        // Basic analysis for any file type
        const lineCount = content.split('\n').length;
        const wordCount = content.split(/\s+/).length;
        if (ext === '.md') {
            usagePatterns.push('Markdown documentation');
        }
        else if (ext === '.json') {
            usagePatterns.push('JSON configuration');
        }
        else if (ext === '.yml' || ext === '.yaml') {
            usagePatterns.push('YAML configuration');
        }
        return {
            filePath: options.filePath,
            functionName: options.functionName,
            summary: `${path.basename(options.filePath)} - ${lineCount} lines, ${wordCount} words`,
            dependencies,
            usagePatterns,
            relatedCode: [],
            recommendations: [],
        };
    }
    async findRelatedCodeReferences(context, depth) {
        const related = [];
        // Find files that import this file or are imported by this file
        for (const dep of context.dependencies) {
            if (dep.filePath && dep.type === 'import') {
                try {
                    await fs.access(dep.filePath);
                    related.push({
                        file: dep.filePath,
                        description: `Imported dependency: ${dep.name}`,
                        relationship: 'imports',
                    });
                }
                catch {
                    // File doesn't exist or can't be accessed
                }
            }
        }
        // Look for files that might import this file
        if (depth > 1) {
            // This would require scanning other files in the project
            // For now, we'll keep it simple
        }
        return related.slice(0, 10); // Limit to 10 related files
    }
    resolveImportPath(importPath, currentFile) {
        if (importPath.startsWith('.')) {
            // Relative import
            const currentDir = path.dirname(currentFile);
            return path.resolve(currentDir, importPath);
        }
        // For node_modules or absolute imports, we'd need more sophisticated resolution
        return undefined;
    }
    async loadCodeContexts() {
        try {
            const data = await fs.readFile(this.codeContextPath, 'utf-8');
            const contextsArray = JSON.parse(data);
            this.codeContexts.clear();
            for (const context of contextsArray) {
                const key = context.functionName ? `${context.filePath}:${context.functionName}` : context.filePath;
                this.codeContexts.set(key, context);
            }
        }
        catch (error) {
            // File doesn't exist or is invalid, start with empty contexts
            this.codeContexts.clear();
        }
    }
    async saveCodeContexts() {
        const contextsArray = Array.from(this.codeContexts.values());
        await fs.writeFile(this.codeContextPath, JSON.stringify(contextsArray, null, 2));
    }
}
//# sourceMappingURL=code-memory.js.map