/**
 * Detection Engine
 *
 * Proprietary security detection engine for Vaspera.
 * Combines AST query, data flow, and control flow analysis
 * for high-confidence vulnerability detection.
 *
 * @module scanners/detection
 */
import { glob } from "glob";
import { runASTQueryEngine } from "./engines/ast-query.js";
import { runDataFlowEngine } from "./engines/data-flow.js";
import { getBuiltinRules, getBuiltinRulesByCategory, getBuiltinRuleById, BUILTIN_RULES } from "./rules/builtin.js";
import { loadRulesFromDirectory } from "./rules/loader.js";
export * from "./types.js";
export { queryAST } from "./engines/ast-query.js";
export { analyzeDataFlow } from "./engines/data-flow.js";
export { loadRulesFromDirectory, loadRuleFromYAML, createRule, RuleValidationError } from "./rules/loader.js";
export { getBuiltinRules, getBuiltinRuleById, getBuiltinRulesByCategory, BUILTIN_RULES };
export async function runDetection(context) {
    const startTime = Date.now();
    const errors = [];
    let allMatches = [];
    const rules = context.rules || getBuiltinRules();
    const enabledRules = rules.filter((r) => r.enabled !== false);
    if (enabledRules.length === 0) {
        return {
            success: true,
            matches: [],
            rulesEvaluated: 0,
            filesAnalyzed: 0,
            duration: Date.now() - startTime,
        };
    }
    let files;
    if (context.files && context.files.length > 0) {
        files = context.files;
    }
    else {
        const includePatterns = context.include || ["**/*.{ts,tsx,js,jsx,py,go,rb}"];
        const excludePatterns = context.exclude || ["**/node_modules/**", "**/dist/**", "**/build/**", "**/.git/**", "**/vendor/**"];
        files = await glob(includePatterns, {
            cwd: context.projectPath,
            ignore: excludePatterns,
            absolute: true,
        });
    }
    if (files.length === 0) {
        return {
            success: true,
            matches: [],
            rulesEvaluated: enabledRules.length,
            filesAnalyzed: 0,
            duration: Date.now() - startTime,
        };
    }
    const astQueryRules = enabledRules.filter((r) => r.engines.astQuery);
    const dataFlowRules = enabledRules.filter((r) => r.engines.dataFlow);
    try {
        if (astQueryRules.length > 0) {
            const astMatches = await runASTQueryEngine(context.projectPath, astQueryRules, files);
            allMatches.push(...astMatches);
        }
    }
    catch (error) {
        errors.push(`AST query engine error: ${error instanceof Error ? error.message : "Unknown error"}`);
    }
    try {
        if (dataFlowRules.length > 0) {
            const dataFlowMatches = await runDataFlowEngine(context.projectPath, dataFlowRules, files);
            allMatches.push(...dataFlowMatches);
        }
    }
    catch (error) {
        errors.push(`Data flow engine error: ${error instanceof Error ? error.message : "Unknown error"}`);
    }
    allMatches = deduplicateMatches(allMatches);
    return {
        success: errors.length === 0,
        matches: allMatches,
        rulesEvaluated: enabledRules.length,
        filesAnalyzed: files.length,
        duration: Date.now() - startTime,
        errors: errors.length > 0 ? errors : undefined,
    };
}
function deduplicateMatches(matches) {
    const seen = new Map();
    for (const match of matches) {
        const key = `${match.ruleId}:${match.file}:${match.line}:${match.column || 0}`;
        const existing = seen.get(key);
        if (!existing || match.confidence > existing.confidence) {
            seen.set(key, match);
        }
    }
    return Array.from(seen.values());
}
export async function runDetectionWithCustomRules(context, customRulesDir) {
    let rules = getBuiltinRules();
    if (customRulesDir) {
        try {
            const customRules = await loadRulesFromDirectory(customRulesDir);
            rules = [...rules, ...customRules];
        }
        catch (error) {
            console.warn(`Failed to load custom rules from ${customRulesDir}:`, error);
        }
    }
    return runDetection({ ...context, rules });
}
export function listAvailableRules() {
    return BUILTIN_RULES.map((r) => ({
        id: r.id,
        name: r.name,
        category: r.category,
        severity: r.severity,
        enabled: r.enabled ?? true,
    }));
}
export function getDetectionCategories() {
    const categories = new Set(BUILTIN_RULES.map((r) => r.category));
    return Array.from(categories).sort();
}
export function enableRule(ruleId) {
    const rule = BUILTIN_RULES.find((r) => r.id === ruleId);
    if (rule) {
        rule.enabled = true;
        return true;
    }
    return false;
}
export function disableRule(ruleId) {
    const rule = BUILTIN_RULES.find((r) => r.id === ruleId);
    if (rule) {
        rule.enabled = false;
        return true;
    }
    return false;
}
//# sourceMappingURL=index.js.map