/**
 * Antagonist Agent
 *
 * A meta-analysis agent that runs AFTER all other agents complete.
 * Synthesizes findings into attack narratives and challenges assumptions.
 *
 * Two modes:
 * 1. Synthesis: "How would an attacker chain these findings?"
 * 2. Challenger: "What did other agents miss? What assumptions are wrong?"
 *
 * @module agents/antagonist
 */
import { DEFAULT_ANTAGONIST_CONFIG } from "./types.js";
import { synthesizeNarratives } from "./synthesizer.js";
import { runChallenger } from "./challenger.js";
import { prioritizeRemediations } from "./prioritizer.js";
import { logger } from "../../logger.js";
export * from "./types.js";
export { synthesizeNarratives, synthesizeNarrativesDeterministic } from "./synthesizer.js";
export { runChallenger, runChallengerDeterministic } from "./challenger.js";
export { prioritizeRemediations, calculatePrioritizationMetrics } from "./prioritizer.js";
/**
 * Run full antagonist analysis
 */
export async function runAntagonistAnalysis(input, config = {}) {
    const startTime = Date.now();
    const fullConfig = { ...DEFAULT_ANTAGONIST_CONFIG, ...config };
    logger.info("antagonist.analysis_started", {
        certificationId: input.certificationId,
        findingsCount: input.findings.length,
        chainsCount: input.exploitChains.length,
        mode: fullConfig.mode,
    });
    const analysisId = `ant-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`;
    let narratives = [];
    let assessments = [];
    let gapAnalysis = {
        untestedAttackVectors: [],
        missingControls: [],
        blindSpots: [],
        recommendations: [],
        coverageScore: 100,
    };
    let prioritization = [];
    let totalTokens = 0;
    try {
        if (fullConfig.mode === "synthesis" || fullConfig.mode === "both") {
            const synthesisResult = await synthesizeNarratives(input.findings, input.exploitChains, input.exfilPaths, fullConfig);
            narratives = synthesisResult.narratives;
            totalTokens += synthesisResult.tokensUsed;
            logger.debug("antagonist.synthesis_complete", {
                narrativesFound: narratives.length,
                tokensUsed: synthesisResult.tokensUsed,
            });
        }
        if (fullConfig.mode === "challenger" || fullConfig.mode === "both") {
            const challengerResult = await runChallenger(input.findings, input.agentSummaries, fullConfig);
            assessments = challengerResult.assessments;
            gapAnalysis = challengerResult.gapAnalysis;
            totalTokens += challengerResult.tokensUsed;
            logger.debug("antagonist.challenger_complete", {
                assessmentsFound: assessments.length,
                coverageScore: gapAnalysis.coverageScore,
                tokensUsed: challengerResult.tokensUsed,
            });
        }
        if (fullConfig.includePrioritization && narratives.length > 0) {
            prioritization = prioritizeRemediations(input.findings, narratives);
            logger.debug("antagonist.prioritization_complete", {
                prioritizedFindings: prioritization.length,
            });
        }
        const summary = generateSummary(narratives, assessments, gapAnalysis, prioritization);
        const duration = Date.now() - startTime;
        logger.info("antagonist.analysis_complete", {
            analysisId,
            narratives: narratives.length,
            assessments: assessments.length,
            coverageScore: gapAnalysis.coverageScore,
            duration,
            tokensUsed: totalTokens,
        });
        return {
            success: true,
            analysisId,
            attackNarratives: narratives,
            challengerAssessments: assessments,
            prioritization,
            gapAnalysis,
            summary,
            duration,
            tokensUsed: totalTokens,
        };
    }
    catch (error) {
        const errorMessage = error instanceof Error ? error.message : String(error);
        logger.error("antagonist.analysis_failed", { error: errorMessage });
        return {
            success: false,
            analysisId,
            attackNarratives: narratives,
            challengerAssessments: assessments,
            prioritization,
            gapAnalysis,
            summary: `Analysis failed: ${errorMessage}`,
            duration: Date.now() - startTime,
            tokensUsed: totalTokens,
            error: errorMessage,
        };
    }
}
/**
 * Generate summary text from analysis results
 */
function generateSummary(narratives, assessments, gapAnalysis, prioritization) {
    const lines = [];
    if (narratives.length > 0) {
        const highLikelihood = narratives.filter((n) => n.likelihood === "high").length;
        const criticalImpact = narratives.filter((n) => n.impact.toLowerCase().includes("complete") || n.impact.toLowerCase().includes("critical")).length;
        lines.push(`Identified ${narratives.length} attack narrative(s): ${highLikelihood} high-likelihood, ${criticalImpact} with critical impact.`);
        const topNarrative = narratives[0];
        if (topNarrative) {
            lines.push(`Most likely attack: "${topNarrative.name}" (${topNarrative.likelihood} likelihood, ${topNarrative.difficulty} difficulty).`);
        }
    }
    else {
        lines.push("No clear attack narratives identified from current findings.");
    }
    if (assessments.length > 0) {
        const fpLikely = assessments.filter((a) => a.type === "false_positive_likely").length;
        const missedChecks = assessments.filter((a) => a.type === "missed_check").length;
        if (fpLikely > 0) {
            lines.push(`Flagged ${fpLikely} potential false positive(s) for review.`);
        }
        if (missedChecks > 0) {
            lines.push(`Identified ${missedChecks} uncovered attack vector(s).`);
        }
    }
    if (gapAnalysis.coverageScore < 80) {
        lines.push(`Coverage score: ${gapAnalysis.coverageScore}%. Missing: ${gapAnalysis.untestedAttackVectors.slice(0, 3).join(", ")}.`);
    }
    if (prioritization.length > 0) {
        const topThree = prioritization.slice(0, 3).map((p) => p.findingId);
        lines.push(`Priority fixes: ${topThree.join(", ")}.`);
    }
    return lines.join(" ");
}
/**
 * Quick antagonist check for a single finding
 */
export async function quickAntagonistCheck(finding, relatedFindings, config = {}) {
    const fullConfig = {
        ...DEFAULT_ANTAGONIST_CONFIG,
        ...config,
        useLlm: false,
        maxNarratives: 3,
    };
    const { narratives } = await synthesizeNarratives([finding, ...relatedFindings], [], [], fullConfig);
    const inAttackPath = narratives.some((n) => n.findingIds.includes(finding.id));
    const chainPotential = narratives
        .filter((n) => n.findingIds.includes(finding.id))
        .flatMap((n) => n.findingIds)
        .filter((id) => id !== finding.id);
    let challengeRisk = "low";
    if (finding.confidence < 50)
        challengeRisk = "high";
    else if (finding.confidence < 70 || finding.file?.includes("test"))
        challengeRisk = "medium";
    return {
        inAttackPath,
        chainPotential: [...new Set(chainPotential)],
        challengeRisk,
    };
}
//# sourceMappingURL=index.js.map