const DEBOUNCE_MS = 500;
// ── SecurityScanner ────────────────────────────
const HARDCODED_SECRET_RE = /\b(api[_-]?key|secret|password|token)\s*[:=]\s*["'][^"']{8,}["']/gi;
const DYNAMIC_SQL_RE = /\b(query|exec|execute|prepare)\s*\(\s*[`'"].*\$\{/gi;
const XSS_PATTERNS_RE = /\b(innerHTML|dangerouslySetInnerHTML)\s*[=:]/gi;
export class SecurityScanner {
    name = 'SecurityScanner';
    shouldRun(trigger) {
        return trigger === 'file_changed' || trigger === 'manual';
    }
    async analyze(context) {
        if (!context.fileContent)
            return [];
        const suggestions = [];
        if (HARDCODED_SECRET_RE.test(context.fileContent)) {
            HARDCODED_SECRET_RE.lastIndex = 0;
            suggestions.push({
                type: 'security',
                title: `Hardcoded secret detected in ${context.filePath ?? 'unknown'}`,
                description: 'Hardcoded secrets should be moved to environment variables or secret management.',
                priority: 1,
                evidence: { filePath: context.filePath, pattern: 'hardcoded_secret' },
                suggestedAction: 'Move secrets to .env file or secret manager',
                riskLevel: 'HIGH',
            });
        }
        if (DYNAMIC_SQL_RE.test(context.fileContent)) {
            DYNAMIC_SQL_RE.lastIndex = 0;
            suggestions.push({
                type: 'security',
                title: `Dynamic SQL construction in ${context.filePath ?? 'unknown'}`,
                description: 'Dynamic SQL construction is vulnerable to SQL injection. Use parameterized queries.',
                priority: 1,
                evidence: { filePath: context.filePath, pattern: 'dynamic_sql' },
                suggestedAction: 'Use parameterized queries instead',
                riskLevel: 'HIGH',
            });
        }
        if (XSS_PATTERNS_RE.test(context.fileContent)) {
            XSS_PATTERNS_RE.lastIndex = 0;
            suggestions.push({
                type: 'security',
                title: `XSS vulnerability pattern in ${context.filePath ?? 'unknown'}`,
                description: 'Using innerHTML or dangerouslySetInnerHTML can lead to XSS vulnerabilities.',
                priority: 2,
                evidence: { filePath: context.filePath, pattern: 'xss' },
                suggestedAction: 'Use safe rendering methods and sanitize user input',
                riskLevel: 'MEDIUM',
            });
        }
        return suggestions;
    }
}
// ── PerformanceDetector ────────────────────────
export class PerformanceDetector {
    name = 'PerformanceDetector';
    shouldRun(trigger) {
        return trigger === 'session_start' || trigger === 'manual';
    }
    async analyze(context) {
        if (!context.fileContent)
            return [];
        const suggestions = [];
        // Detect N+1 query pattern (loop + query)
        if (/for\s*\(.*\)\s*\{[^}]*\.(query|find|get|select)\s*\(/gs.test(context.fileContent)) {
            suggestions.push({
                type: 'performance',
                title: `Potential N+1 query in ${context.filePath ?? 'unknown'}`,
                description: 'Database query inside a loop may cause N+1 performance issues.',
                priority: 2,
                evidence: { filePath: context.filePath, pattern: 'n_plus_1' },
                suggestedAction: 'Use batch queries or joins instead',
            });
        }
        return suggestions;
    }
}
// ── QualityChecker ──────────────────────────────
const TODO_RE = /\/\/\s*TODO\b/g;
const HIGH_COMPLEXITY_RE = /(?:if|else|for|while|switch|catch|&&|\|\|)/g;
export class QualityChecker {
    name = 'QualityChecker';
    shouldRun(trigger) {
        return trigger === 'file_changed' || trigger === 'build_complete' || trigger === 'manual';
    }
    async analyze(context) {
        if (!context.fileContent)
            return [];
        const suggestions = [];
        // Check for abandoned TODOs
        const todoMatches = context.fileContent.match(TODO_RE);
        if (todoMatches && todoMatches.length > 3) {
            suggestions.push({
                type: 'quality',
                title: `${todoMatches.length} TODOs in ${context.filePath ?? 'unknown'}`,
                description: `Found ${todoMatches.length} TODO comments that may need attention.`,
                priority: 3,
                evidence: { filePath: context.filePath, todoCount: todoMatches.length },
                suggestedAction: 'Review and resolve TODO items',
            });
        }
        // Check complexity (rough heuristic)
        const lines = context.fileContent.split('\n');
        const complexityMatches = context.fileContent.match(HIGH_COMPLEXITY_RE);
        if (complexityMatches && lines.length > 0) {
            const density = complexityMatches.length / lines.length;
            if (density > 0.3) {
                suggestions.push({
                    type: 'quality',
                    title: `High complexity in ${context.filePath ?? 'unknown'}`,
                    description: `Complexity density ${(density * 100).toFixed(0)}% exceeds threshold.`,
                    priority: 2,
                    evidence: { filePath: context.filePath, complexityDensity: density },
                    suggestedAction: 'Consider refactoring to reduce complexity',
                });
            }
        }
        return suggestions;
    }
}
// ── DependencyMonitor ───────────────────────────
export class DependencyMonitor {
    name = 'DependencyMonitor';
    shouldRun(trigger) {
        return trigger === 'scheduled' || trigger === 'manual';
    }
    async analyze(context) {
        if (!context.fileContent)
            return [];
        // Parse package.json for basic checks
        try {
            const pkg = JSON.parse(context.fileContent);
            const suggestions = [];
            const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
            // Check for wildcard versions
            for (const [name, version] of Object.entries(allDeps)) {
                if (version === '*' || version === 'latest') {
                    suggestions.push({
                        type: 'dependency',
                        title: `Unpinned dependency: ${name}`,
                        description: `${name} uses '${version}' version which is not pinned.`,
                        priority: 2,
                        evidence: { package: name, version },
                        suggestedAction: `Pin ${name} to a specific version`,
                    });
                }
            }
            return suggestions;
        }
        catch {
            return [];
        }
    }
}
// ── ProactiveAnalyzer (Orchestrator) ────────────
export class ProactiveAnalyzer {
    modules;
    store;
    eventBus;
    debounceTimers = new Map();
    constructor(deps) {
        this.store = deps.store;
        this.eventBus = deps.eventBus;
        this.modules = deps.modules ?? [
            new SecurityScanner(),
            new PerformanceDetector(),
            new QualityChecker(),
            new DependencyMonitor(),
        ];
    }
    async analyze(context) {
        if (context.filePath && context.trigger === 'file_changed') {
            return this.analyzeDebounced(context);
        }
        return this.runAnalysis(context);
    }
    getModules() {
        return this.modules;
    }
    clearDebounce() {
        for (const timer of this.debounceTimers.values()) {
            clearTimeout(timer);
        }
        this.debounceTimers.clear();
    }
    analyzeDebounced(context) {
        const key = context.filePath;
        const existing = this.debounceTimers.get(key);
        if (existing)
            clearTimeout(existing);
        return new Promise((resolve) => {
            this.debounceTimers.set(key, setTimeout(async () => {
                this.debounceTimers.delete(key);
                const results = await this.runAnalysis(context);
                resolve(results);
            }, DEBOUNCE_MS));
        });
    }
    async runAnalysis(context) {
        const allSuggestions = [];
        for (const mod of this.modules) {
            if (!mod.shouldRun(context.trigger))
                continue;
            try {
                const suggestions = await mod.analyze(context);
                for (const s of suggestions) {
                    this.store.create({
                        ...s,
                        sourceModule: mod.name,
                    });
                    allSuggestions.push(s);
                }
            }
            catch {
                // Module failure should not break analysis
            }
        }
        if (allSuggestions.length > 0) {
            this.emitSuggestionCreated(allSuggestions.length, context.trigger);
        }
        return allSuggestions;
    }
    emitSuggestionCreated(count, trigger) {
        try {
            this.eventBus.emit('suggestion_created', {
                eventType: 'suggestion_created',
                payload: { count, trigger },
                sourceAgentId: 'proactive-analyzer',
            });
        }
        catch {
            // Non-critical
        }
    }
}
//# sourceMappingURL=ProactiveAnalyzer.js.map