/**
 * Enterprise Certification System - Consensus Algorithm
 *
 * This module implements the weighted multi-agent consensus algorithm for
 * calculating certification scores and levels. It handles:
 * - Individual agent score calculation with severity penalties
 * - Cross-verification multipliers (confirmed findings penalized more, disputed less)
 * - Weighted aggregation across all agents
 * - Certification level determination based on thresholds and critical findings
 *
 * @module certification/consensus
 */
import { AGENT_WEIGHTS, SEVERITY_PENALTIES, CERTIFICATION_THRESHOLDS, } from "./types.js";
/**
 * Calculate the verification multiplier for a finding based on cross-verification results.
 *
 * The multiplier adjusts the severity penalty:
 * - More confirmations from other agents = higher multiplier (max 1.6x for 3+ confirmations)
 * - More disputes = lower multiplier (min 0.2x if heavily disputed)
 * - No verifications or balanced = 1.0x (no adjustment)
 *
 * @param finding - The finding to calculate multiplier for
 * @returns Multiplier value between 0.2 and 1.6
 * @internal
 */
function calculateVerificationMultiplier(finding) {
    if (finding.verifications.length === 0)
        return 1.0;
    const confirmations = finding.verifications.filter((v) => v.verdict === "confirmed").length;
    const disputes = finding.verifications.filter((v) => v.verdict === "disputed").length;
    const net = confirmations - disputes;
    // More confirmations = higher multiplier (max 1.6x for 3+ confirmations)
    if (net > 0)
        return Math.min(1.6, 1 + net * 0.2);
    // More disputes = lower multiplier (min 0.2x if heavily disputed)
    if (net < 0)
        return Math.max(0.2, 1 + net * 0.3);
    return 1.0;
}
/**
 * Minimum findings expected per agent for a thorough audit.
 * Agents reporting zero findings are flagged as potentially incomplete.
 * @internal
 */
const MIN_EXPECTED_FINDINGS = 1;
/**
 * Calculate an individual agent's score based on its findings.
 *
 * Score starts at 100 and is reduced by severity penalties:
 * - Critical: -25 points
 * - High: -10 points
 * - Medium: -3 points
 * - Low: -1 point
 * - Info: 0 points
 *
 * Each penalty is multiplied by:
 * - Finding confidence (0-100 normalized to 0-1)
 * - Cross-verification multiplier (0.2-1.6)
 *
 * Zero findings results in low confidence (50) as it may indicate incomplete audit.
 *
 * @param findings - Array of findings from an agent
 * @returns Object with score (0-100) and confidence (0-100)
 * @internal
 */
function calculateAgentScore(findings) {
    let score = 100;
    let totalConfidence = 0;
    let findingCount = 0;
    for (const finding of findings) {
        // Get base penalty for severity
        const basePenalty = SEVERITY_PENALTIES[finding.severity];
        // Adjust by confidence (0-100 normalized to 0-1)
        const confidenceMultiplier = finding.confidence / 100;
        // Adjust by cross-verification
        const verificationMultiplier = calculateVerificationMultiplier(finding);
        // Calculate final penalty
        const penalty = basePenalty * confidenceMultiplier * verificationMultiplier;
        score -= penalty;
        totalConfidence += finding.confidence;
        findingCount++;
    }
    // Clamp score to 0-100
    score = Math.max(0, Math.min(100, score));
    // Zero findings is suspicious - reduce confidence significantly
    // A thorough audit should find at least informational items
    if (findingCount < MIN_EXPECTED_FINDINGS) {
        // Low confidence in a "perfect" audit
        return { score, confidence: 50 };
    }
    // Average confidence
    const avgConfidence = totalConfidence / findingCount;
    return { score, confidence: avgConfidence };
}
/**
 * Count findings by severity across all agents
 */
function countFindingsBySeverity(certification) {
    const counts = {
        critical: 0,
        high: 0,
        medium: 0,
        low: 0,
        info: 0,
    };
    for (const agentFindings of Object.values(certification.agents)) {
        if (agentFindings) {
            for (const finding of agentFindings.findings) {
                counts[finding.severity]++;
            }
        }
    }
    return counts;
}
/**
 * Calculate cross-verification rate
 */
function calculateCrossVerificationRate(certification) {
    let totalFindings = 0;
    let verifiedFindings = 0;
    for (const agentFindings of Object.values(certification.agents)) {
        if (agentFindings) {
            for (const finding of agentFindings.findings) {
                totalFindings++;
                if (finding.verifications.length > 0) {
                    verifiedFindings++;
                }
            }
        }
    }
    return totalFindings > 0 ? verifiedFindings / totalFindings : 1.0;
}
/**
 * Determine certification level from score
 */
function determineCertificationLevel(score, bySeverity) {
    // Critical findings = BLOCKED regardless of score
    if (bySeverity.critical > 0) {
        return "BLOCKED";
    }
    // Multiple high findings with low score = BLOCKED
    if (bySeverity.high >= 3 && score < 50) {
        return "BLOCKED";
    }
    // Score-based thresholds
    if (score >= CERTIFICATION_THRESHOLDS.CERTIFIED) {
        // Certified also requires no high severity issues
        if (bySeverity.high === 0) {
            return "CERTIFIED";
        }
        return "APPROVED";
    }
    if (score >= CERTIFICATION_THRESHOLDS.APPROVED) {
        return "APPROVED";
    }
    if (score >= CERTIFICATION_THRESHOLDS.REVIEW_REQUIRED) {
        return "REVIEW_REQUIRED";
    }
    return "BLOCKED";
}
/**
 * Calculate the consensus result for a certification across all agents.
 *
 * This is the main scoring function that:
 * 1. Calculates individual scores for each completed agent
 * 2. Applies agent weights (Security 30%, Reliability 25%, TypeSafety 15%,
 *    Performance 15%, Quality 10%, RedTeam 5%)
 * 3. Computes weighted overall score
 * 4. Counts findings by severity
 * 5. Calculates cross-verification rate
 * 6. Determines certification level based on score and critical findings
 *
 * @param certification - The full certification data including all agent findings
 * @returns ConsensusResult with overall score, level, and detailed metrics
 *
 * @example
 * ```typescript
 * const certification = await getCertification(projectPath, certId);
 * const consensus = calculateConsensus(certification);
 * console.log(`Score: ${consensus.overall_score}/100`);
 * console.log(`Level: ${consensus.certification_level}`);
 * ```
 */
export function calculateConsensus(certification) {
    const agentScores = {};
    const agentConfidences = {};
    let weightedScore = 0;
    let totalWeight = 0;
    let totalFindings = 0;
    // Calculate scores for each agent
    const allAgents = ["security", "reliability", "typesafety", "performance", "quality", "redteam"];
    for (const agent of allAgents) {
        const agentFindings = certification.agents[agent];
        if (agentFindings && agentFindings.status === "completed") {
            const { score, confidence } = calculateAgentScore(agentFindings.findings);
            agentScores[agent] = score;
            agentConfidences[agent] = confidence;
            // Weighted contribution to overall score
            // Factor in confidence - low confidence agents contribute less
            const weight = AGENT_WEIGHTS[agent];
            const confidenceMultiplier = confidence / 100;
            weightedScore += score * weight * confidenceMultiplier;
            totalWeight += weight * confidenceMultiplier;
            totalFindings += agentFindings.findings.length;
        }
    }
    // Normalize weighted score
    const overallScore = totalWeight > 0 ? Math.round(weightedScore / totalWeight) : 0;
    // Count findings by severity
    const bySeverity = countFindingsBySeverity(certification);
    // Calculate cross-verification rate
    const crossVerificationRate = calculateCrossVerificationRate(certification);
    // Count red team challenges
    const redTeamChallengesTotal = certification.red_team_challenges.length;
    const redTeamChallengesAccepted = certification.red_team_challenges.filter((c) => c.resolution?.accepted).length;
    // Determine certification level
    const certificationLevel = determineCertificationLevel(overallScore, bySeverity);
    return {
        overall_score: overallScore,
        certification_level: certificationLevel,
        agent_scores: agentScores,
        agent_confidences: agentConfidences,
        total_findings: totalFindings,
        by_severity: bySeverity,
        cross_verification_rate: crossVerificationRate,
        red_team_challenges_accepted: redTeamChallengesAccepted,
        red_team_challenges_total: redTeamChallengesTotal,
        calculated_at: new Date().toISOString(),
    };
}
/**
 * Check if a certification is ready to be finalized.
 *
 * A certification can be finalized when:
 * - All requested agents have completed their audits
 * - All critical findings have been cross-verified by at least one other agent
 *
 * Additionally, this function returns warnings for suspicious conditions:
 * - Agents reporting zero findings (may indicate incomplete audit)
 * - Total findings across all agents is zero (certification may not be trustworthy)
 *
 * @param certification - The certification to check
 * @returns Object containing:
 *   - ready: boolean indicating if certification can be finalized
 *   - missing: array of blocking issues that prevent finalization
 *   - warnings: array of non-blocking concerns to review
 *
 * @example
 * ```typescript
 * const { ready, missing, warnings } = canFinalize(certification);
 * if (!ready) {
 *   console.log('Cannot finalize:', missing);
 * }
 * if (warnings.length > 0) {
 *   console.log('Warnings:', warnings);
 * }
 * ```
 */
export function canFinalize(certification) {
    const missing = [];
    const warnings = [];
    const requested = certification.metadata.agents_requested;
    const completed = certification.metadata.agents_completed;
    // Check all requested agents completed
    for (const agent of requested) {
        if (!completed.includes(agent)) {
            missing.push(`Agent ${agent} not completed`);
        }
    }
    // Check critical findings are cross-verified
    for (const agentFindings of Object.values(certification.agents)) {
        if (agentFindings) {
            for (const finding of agentFindings.findings) {
                if (finding.severity === "critical" && finding.verifications.length === 0) {
                    missing.push(`Critical finding ${finding.id} not cross-verified`);
                }
            }
        }
    }
    // Warn about empty audits (suspicious)
    for (const agent of requested) {
        const agentFindings = certification.agents[agent];
        if (agentFindings && agentFindings.findings.length === 0) {
            warnings.push(`Agent ${agent} reported zero findings - audit may be incomplete`);
        }
    }
    // Warn if total findings are suspiciously low
    const totalFindings = Object.values(certification.agents).reduce((sum, a) => sum + (a?.findings.length ?? 0), 0);
    if (totalFindings === 0) {
        warnings.push("No findings across all agents - certification may not be trustworthy");
    }
    return {
        ready: missing.length === 0,
        missing,
        warnings,
    };
}
/**
 * Generate a human-readable summary of a certification consensus result.
 *
 * The summary includes:
 * - Certification level with color-coded emoji indicator
 * - Overall score out of 100
 * - Breakdown of findings by severity
 * - Cross-verification rate as percentage
 * - Red team challenge statistics
 *
 * Level indicators:
 * - 🟢 CERTIFIED (90-100)
 * - 🟡 APPROVED (70-89)
 * - 🟠 REVIEW_REQUIRED (40-69)
 * - 🔴 BLOCKED (0-39)
 *
 * @param consensus - The consensus result to summarize
 * @returns Multi-line string formatted for display
 *
 * @example
 * ```typescript
 * const consensus = calculateConsensus(certification);
 * console.log(getCertificationSummary(consensus));
 * // Output:
 * // 🟡 APPROVED
 * // Score: 85/100
 * //
 * // Findings: 15
 * //   Critical: 0
 * //   High: 2
 * //   ...
 * ```
 */
export function getCertificationSummary(consensus) {
    const levelEmoji = {
        CERTIFIED: "🟢",
        APPROVED: "🟡",
        REVIEW_REQUIRED: "🟠",
        BLOCKED: "🔴",
    };
    const lines = [
        `${levelEmoji[consensus.certification_level]} ${consensus.certification_level}`,
        `Score: ${consensus.overall_score}/100`,
        ``,
        `Findings: ${consensus.total_findings}`,
        `  Critical: ${consensus.by_severity.critical}`,
        `  High: ${consensus.by_severity.high}`,
        `  Medium: ${consensus.by_severity.medium}`,
        `  Low: ${consensus.by_severity.low}`,
        ``,
        `Cross-verification: ${Math.round(consensus.cross_verification_rate * 100)}%`,
        `Red team: ${consensus.red_team_challenges_accepted}/${consensus.red_team_challenges_total} challenges accepted`,
    ];
    return lines.join("\n");
}
//# sourceMappingURL=consensus.js.map