/**
 * Progressive Summary Tool
 *
 * Provides grouped and filtered views of certification findings
 * to make large result sets more actionable.
 *
 * @module certification/summary
 */
/**
 * Effort estimates per severity (in hours)
 */
const EFFORT_PER_SEVERITY = {
    critical: 2,
    high: 1,
    medium: 0.5,
    low: 0.25,
    info: 0,
};
/**
 * Generate a comprehensive summary of certification findings
 */
export function generateSummary(certification) {
    const allFindings = [];
    // Collect all findings
    for (const [agent, agentData] of Object.entries(certification.agents)) {
        if (agentData) {
            for (const finding of agentData.findings) {
                allFindings.push({ agent: agent, finding });
            }
        }
    }
    // Group by severity
    const bySeverity = groupBySeverity(allFindings);
    // Group by agent
    const byAgent = groupByAgent(allFindings, certification);
    // Group by file
    const byFile = groupByFile(allFindings);
    // Group by category
    const byCategory = groupByCategory(allFindings);
    // Calculate effort
    const estimatedEffort = calculateEffort(allFindings);
    // Get top priority findings (critical + high)
    const topPriority = allFindings
        .filter((f) => f.finding.severity === "critical" || f.finding.severity === "high")
        .sort((a, b) => {
        const severityOrder = {
            critical: 0,
            high: 1,
            medium: 2,
            low: 3,
            info: 4,
        };
        return (severityOrder[a.finding.severity] - severityOrder[b.finding.severity] ||
            b.finding.confidence - a.finding.confidence);
    })
        .slice(0, 10)
        .map((f) => f.finding);
    return {
        totalFindings: allFindings.length,
        bySeverity,
        byAgent,
        byFile,
        byCategory,
        estimatedEffort,
        topPriority,
    };
}
function groupBySeverity(findings) {
    const result = {
        critical: { count: 0, files: 0, findings: [], estimatedHours: "0" },
        high: { count: 0, files: 0, findings: [], estimatedHours: "0" },
        medium: { count: 0, files: 0, findings: [], estimatedHours: "0" },
        low: { count: 0, files: 0, findings: [], estimatedHours: "0" },
        info: { count: 0, files: 0, findings: [], estimatedHours: "0" },
    };
    const filesBySeverity = {
        critical: new Set(),
        high: new Set(),
        medium: new Set(),
        low: new Set(),
        info: new Set(),
    };
    for (const { finding } of findings) {
        result[finding.severity].count++;
        result[finding.severity].findings.push(finding.id);
        if (finding.file) {
            filesBySeverity[finding.severity].add(finding.file);
        }
    }
    for (const severity of Object.keys(result)) {
        result[severity].files = filesBySeverity[severity].size;
        const hours = result[severity].count * EFFORT_PER_SEVERITY[severity];
        result[severity].estimatedHours = formatHours(hours);
    }
    return result;
}
function groupByAgent(findings, certification) {
    const result = {};
    const byAgent = new Map();
    for (const { agent, finding } of findings) {
        if (!byAgent.has(agent))
            byAgent.set(agent, []);
        byAgent.get(agent).push(finding);
    }
    for (const [agent, agentFindings] of byAgent) {
        result[agent] = {
            count: agentFindings.length,
            score: certification.consensus?.agent_scores[agent] ?? 0,
            confidence: certification.consensus?.agent_confidences[agent] ?? 0,
            topFindings: agentFindings
                .sort((a, b) => {
                const severityOrder = {
                    critical: 0,
                    high: 1,
                    medium: 2,
                    low: 3,
                    info: 4,
                };
                return severityOrder[a.severity] - severityOrder[b.severity];
            })
                .slice(0, 5)
                .map((f) => f.id),
        };
    }
    return result;
}
function groupByFile(findings) {
    const byFile = new Map();
    for (const { finding } of findings) {
        const file = finding.file || "(no file)";
        if (!byFile.has(file)) {
            byFile.set(file, {
                severities: { critical: 0, high: 0, medium: 0, low: 0, info: 0 },
                findings: [],
            });
        }
        byFile.get(file).severities[finding.severity]++;
        byFile.get(file).findings.push(finding.id);
    }
    return Array.from(byFile.entries())
        .map(([file, data]) => ({
        file,
        issueCount: data.findings.length,
        severities: data.severities,
        findings: data.findings,
    }))
        .sort((a, b) => {
        // Sort by critical count, then high, then total
        const critDiff = b.severities.critical - a.severities.critical;
        if (critDiff !== 0)
            return critDiff;
        const highDiff = b.severities.high - a.severities.high;
        if (highDiff !== 0)
            return highDiff;
        return b.issueCount - a.issueCount;
    })
        .slice(0, 20);
}
function groupByCategory(findings) {
    const byCategory = new Map();
    for (const { finding } of findings) {
        const category = finding.category || "uncategorized";
        if (!byCategory.has(category)) {
            byCategory.set(category, { findings: [] });
        }
        byCategory.get(category).findings.push(finding);
    }
    return Array.from(byCategory.entries())
        .map(([category, data]) => {
        // Determine highest severity in category
        const severityOrder = {
            critical: 0,
            high: 1,
            medium: 2,
            low: 3,
            info: 4,
        };
        const highestSeverity = data.findings.reduce((highest, f) => severityOrder[f.severity] < severityOrder[highest] ? f.severity : highest, "info");
        return {
            category,
            count: data.findings.length,
            severity: highestSeverity,
            findings: data.findings.map((f) => f.id),
        };
    })
        .sort((a, b) => {
        const severityOrder = {
            critical: 0,
            high: 1,
            medium: 2,
            low: 3,
            info: 4,
        };
        return severityOrder[a.severity] - severityOrder[b.severity] || b.count - a.count;
    });
}
function calculateEffort(findings) {
    const hours = {
        critical: 0,
        high: 0,
        medium: 0,
        low: 0,
        info: 0,
    };
    for (const { finding } of findings) {
        hours[finding.severity] += EFFORT_PER_SEVERITY[finding.severity];
    }
    const total = Object.values(hours).reduce((sum, h) => sum + h, 0);
    return {
        totalHours: formatHours(total),
        critical: formatHours(hours.critical),
        high: formatHours(hours.high),
        medium: formatHours(hours.medium),
        low: formatHours(hours.low),
    };
}
function formatHours(hours) {
    if (hours === 0)
        return "0 hours";
    if (hours < 1)
        return `${Math.round(hours * 60)} minutes`;
    if (hours === 1)
        return "1 hour";
    if (hours < 8)
        return `${hours.toFixed(1)} hours`;
    const days = hours / 8;
    if (days < 5)
        return `${days.toFixed(1)} days`;
    return `${Math.round(days / 5)} weeks`;
}
/**
 * Filter findings by various criteria
 */
export function filterFindings(certification, options) {
    const results = [];
    for (const [agent, agentData] of Object.entries(certification.agents)) {
        if (options.agents && !options.agents.includes(agent)) {
            continue;
        }
        if (agentData) {
            for (const finding of agentData.findings) {
                // Filter by severity
                if (options.severity && !options.severity.includes(finding.severity)) {
                    continue;
                }
                // Filter by category
                if (options.categories && !options.categories.includes(finding.category)) {
                    continue;
                }
                // Filter by file
                if (options.files && finding.file && !options.files.some((f) => finding.file.includes(f))) {
                    continue;
                }
                // Filter by confidence
                if (options.minConfidence && finding.confidence < options.minConfidence) {
                    continue;
                }
                // Filter by instances
                if (options.hasInstances && (!finding.instances || finding.instances.length === 0)) {
                    continue;
                }
                results.push(finding);
            }
        }
    }
    return results;
}
/**
 * Get actionable next steps based on findings
 */
export function getActionItems(certification) {
    const summary = generateSummary(certification);
    const actions = [];
    if (summary.bySeverity.critical.count > 0) {
        actions.push(`🚨 Fix ${summary.bySeverity.critical.count} critical issues immediately (${summary.bySeverity.critical.estimatedHours})`);
    }
    if (summary.bySeverity.high.count > 0) {
        actions.push(`⚠️ Address ${summary.bySeverity.high.count} high-priority issues (${summary.bySeverity.high.estimatedHours})`);
    }
    // Top files needing attention
    const topFiles = summary.byFile.slice(0, 3);
    if (topFiles.length > 0) {
        actions.push(`📁 Focus on these files first: ${topFiles.map((f) => `${f.file} (${f.issueCount} issues)`).join(", ")}`);
    }
    // Agent recommendations
    for (const [agent, data] of Object.entries(summary.byAgent)) {
        if (data.score < 70) {
            actions.push(`🔧 ${agent}: Score ${data.score}/100 - needs attention`);
        }
    }
    if (actions.length === 0) {
        actions.push("✅ No critical actions required");
    }
    return actions;
}
//# sourceMappingURL=summary.js.map