/**
 * Compliance Mapper
 *
 * Maps security findings to compliance framework controls.
 *
 * @module compliance/mapper
 */
import { SOC2_CONTROLS } from "./soc2.js";
import { ISO27001_CONTROLS } from "./iso27001.js";
import { PCI_DSS_CONTROLS } from "./pci-dss.js";
import { HIPAA_CONTROLS } from "./hipaa.js";
import { CIS_CONTROLS } from "./cis.js";
import { GDPR_CONTROLS } from "./gdpr.js";
import { NIST_800_53_CONTROLS } from "./nist-800-53.js";
import { CFR42_PART2_CONTROLS } from "./cfr42-part2.js";
import { randomUUID } from "crypto";
/**
 * Severity weight for scoring
 */
const SEVERITY_WEIGHT = {
    critical: 100,
    high: 75,
    medium: 50,
    low: 25,
    info: 10,
};
/**
 * Severity threshold check
 */
const SEVERITY_ORDER = {
    critical: 4,
    high: 3,
    medium: 2,
    low: 1,
    info: 0,
};
/**
 * Get controls for a framework
 */
export function getControlsForFramework(framework) {
    switch (framework) {
        case "SOC2":
            return SOC2_CONTROLS;
        case "ISO27001":
            return ISO27001_CONTROLS;
        case "PCI-DSS":
            return PCI_DSS_CONTROLS;
        case "HIPAA":
            return HIPAA_CONTROLS;
        case "42-CFR-PART-2":
            return CFR42_PART2_CONTROLS;
        case "CIS":
            return CIS_CONTROLS;
        case "GDPR":
            return GDPR_CONTROLS;
        case "NIST-800-53":
            return NIST_800_53_CONTROLS;
        default:
            return [];
    }
}
/**
 * Check if a finding matches a control
 */
export function findingMatchesControl(finding, control) {
    // Check category match
    if (control.findingCategories.includes(finding.category)) {
        return true;
    }
    // Check CWE match if available
    if (control.cweIds && finding.cwe_ids && finding.cwe_ids.length > 0) {
        if (control.cweIds.some((cwe) => finding.cwe_ids.some((fCwe) => fCwe.includes(cwe) || cwe.includes(fCwe)))) {
            return true;
        }
    }
    // Check keyword match in description
    const descLower = finding.description.toLowerCase();
    if (control.keywords.some((kw) => descLower.includes(kw.toLowerCase()))) {
        return true;
    }
    return false;
}
/**
 * Check if finding severity meets control threshold
 */
export function meetsSeverityThreshold(finding, control) {
    if (!control.severityThreshold)
        return true;
    return SEVERITY_ORDER[finding.severity] >= SEVERITY_ORDER[control.severityThreshold];
}
/**
 * Map findings to controls for a framework
 */
export function mapFindingsToControls(findings, framework) {
    const controls = getControlsForFramework(framework);
    const result = [];
    for (const control of controls) {
        const matchedFindings = findings.filter((f) => findingMatchesControl(f, control) && meetsSeverityThreshold(f, control));
        // Determine status based on findings
        let status = "compliant";
        let riskLevel = "low";
        if (matchedFindings.length > 0) {
            const maxSeverity = matchedFindings.reduce((max, f) => {
                return SEVERITY_ORDER[f.severity] > SEVERITY_ORDER[max] ? f.severity : max;
            }, "info");
            if (maxSeverity === "critical" || maxSeverity === "high") {
                status = "non_compliant";
                riskLevel = maxSeverity === "critical" ? "critical" : "high";
            }
            else {
                status = "at_risk";
                riskLevel = maxSeverity === "medium" ? "medium" : "low";
            }
        }
        result.push({
            control,
            findings: matchedFindings,
            status,
            riskLevel,
        });
    }
    return result;
}
/**
 * Calculate compliance status from control mappings
 */
export function calculateComplianceStatus(framework, controlMappings) {
    const totalControls = controlMappings.length;
    const compliant = controlMappings.filter((c) => c.status === "compliant").length;
    const atRisk = controlMappings.filter((c) => c.status === "at_risk").length;
    const nonCompliant = controlMappings.filter((c) => c.status === "non_compliant").length;
    // Calculate compliance score (percentage of controls not non-compliant)
    const complianceScore = Math.round(((compliant + atRisk) / totalControls) * 100);
    // Calculate risk score based on findings severity
    let totalRisk = 0;
    let maxRisk = 0;
    for (const mapping of controlMappings) {
        maxRisk += SEVERITY_WEIGHT.critical;
        if (mapping.findings.length > 0) {
            const maxFindingSeverity = mapping.findings.reduce((max, f) => {
                return SEVERITY_WEIGHT[f.severity] > SEVERITY_WEIGHT[max] ? f.severity : max;
            }, "info");
            totalRisk += SEVERITY_WEIGHT[maxFindingSeverity];
        }
    }
    const riskScore = maxRisk > 0 ? Math.round((totalRisk / maxRisk) * 100) : 0;
    return {
        framework,
        totalControls,
        controlsCovered: compliant,
        controlsAtRisk: atRisk,
        controlsNonCompliant: nonCompliant,
        complianceScore,
        riskScore,
    };
}
/**
 * Generate recommendations from control mappings
 */
export function generateRecommendations(controlMappings) {
    const recommendations = [];
    // Sort by risk level
    const sorted = [...controlMappings]
        .filter((c) => c.status !== "compliant")
        .sort((a, b) => {
        const riskOrder = { critical: 4, high: 3, medium: 2, low: 1 };
        return riskOrder[b.riskLevel] - riskOrder[a.riskLevel];
    });
    for (const mapping of sorted) {
        const priority = mapping.riskLevel;
        // Group findings by category for remediation steps
        const categories = [...new Set(mapping.findings.map((f) => f.category))];
        const remediationSteps = categories.map((cat) => {
            const count = mapping.findings.filter((f) => f.category === cat).length;
            return `Address ${count} ${cat} finding(s) affecting this control`;
        });
        if (remediationSteps.length === 0) {
            remediationSteps.push("Review and implement control requirements");
        }
        const effort = mapping.riskLevel === "critical" || mapping.findings.length > 5
            ? "weeks"
            : mapping.riskLevel === "high" || mapping.findings.length > 2
                ? "days"
                : "hours";
        recommendations.push({
            controlId: mapping.control.id,
            priority,
            title: `Remediate ${mapping.control.title}`,
            description: `Control ${mapping.control.id} has ${mapping.findings.length} finding(s) that put it at ${mapping.status === "non_compliant" ? "non-compliance" : "risk"}.`,
            remediationSteps,
            estimatedEffort: effort,
        });
    }
    return recommendations;
}
/**
 * Generate a compliance report for a framework
 */
export function generateComplianceReport(findings, framework, projectPath, certificationId) {
    const controlMappings = mapFindingsToControls(findings, framework);
    const status = calculateComplianceStatus(framework, controlMappings);
    const recommendations = generateRecommendations(controlMappings);
    const compliantControls = controlMappings
        .filter((c) => c.status === "compliant")
        .map((c) => c.control);
    const atRiskControls = controlMappings.filter((c) => c.status === "at_risk");
    const nonCompliantControls = controlMappings.filter((c) => c.status === "non_compliant");
    return {
        id: `compliance-${randomUUID().slice(0, 8)}`,
        generatedAt: new Date().toISOString(),
        projectPath,
        certificationId,
        framework,
        status,
        controls: controlMappings,
        compliantControls,
        atRiskControls,
        nonCompliantControls,
        recommendations,
    };
}
/**
 * Generate a multi-framework compliance report
 */
export function generateMultiFrameworkReport(findings, frameworks, projectPath, certificationId) {
    const frameworkStatuses = {};
    const allRecommendations = [];
    for (const framework of frameworks) {
        const controlMappings = mapFindingsToControls(findings, framework);
        frameworkStatuses[framework] = calculateComplianceStatus(framework, controlMappings);
        allRecommendations.push(...generateRecommendations(controlMappings));
    }
    // Deduplicate and prioritize recommendations
    const seenControls = new Set();
    const prioritizedRecommendations = allRecommendations
        .sort((a, b) => {
        const priorityOrder = { critical: 4, high: 3, medium: 2, low: 1 };
        return priorityOrder[b.priority] - priorityOrder[a.priority];
    })
        .filter((r) => {
        if (seenControls.has(r.controlId))
            return false;
        seenControls.add(r.controlId);
        return true;
    });
    return {
        id: `multi-compliance-${randomUUID().slice(0, 8)}`,
        generatedAt: new Date().toISOString(),
        projectPath,
        certificationId,
        frameworks: frameworkStatuses,
        prioritizedRecommendations,
    };
}
//# sourceMappingURL=mapper.js.map