"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildSecurityDetailed = buildSecurityDetailed;
exports.formatSecurityDetailedMarkdown = formatSecurityDetailedMarkdown;
const remediation_1 = require("../remediation");
const actions_1 = require("./actions");
const scoring_1 = require("../../scoring");
const tools_unavailable_prose_1 = require("../tools/tools-unavailable-prose");
const finding_context_1 = require("../../explore/finding-context");
function buildSecurityDetailed(report, graphContext) {
    const input = (0, actions_1.countsFromReport)(report);
    const scoreFromInput = (i) => (0, scoring_1.evaluateSpec)(scoring_1.SECURITY_SCORING_SPEC, i);
    const actions = (0, remediation_1.rank)((0, actions_1.buildSecurityActions)(report), input, scoreFromInput);
    return {
        ...report,
        // v13 carries the unified scorer output; same path the health
        // audit's Security dimension uses, identical scores.
        schemaVersion: '13',
        securityScore: scoreFromInput(input).score,
        actions,
        ...(graphContext ? { graphContext } : {}),
    };
}
const SEV_ORDER = { critical: 0, high: 1, medium: 2, low: 3 };
function formatSecurityDetailedMarkdown(detailed, elapsed) {
    const L = [];
    const s = detailed.summary.findings;
    const d = detailed.summary.dependencies;
    L.push('# Vulnerability Scan — Detailed');
    L.push('');
    L.push(`**Date:** ${detailed.analyzedAt.slice(0, 10)}`);
    L.push(`**Repository:** ${detailed.repo}`);
    L.push(`**Branch:** ${detailed.branch} (${detailed.commitSha})`);
    L.push(`**Security Score:** ${detailed.securityScore}/100`);
    L.push(`**Schema version:** ${detailed.schemaVersion}`);
    L.push('');
    L.push('---');
    L.push('');
    // Summary — two independent axes (see formatSecurityReport in
    // index.ts for the same rationale). Code findings vs dependency
    // vulnerabilities are NOT summed naïvely; each has its own
    // remediation owner (your team patches code, you upgrade deps).
    L.push('## Summary');
    L.push('');
    L.push('Two independent axes:');
    L.push('- **Code findings** — vulnerabilities in source your team owns. Fix by patching code.');
    L.push('- **Dependency vulnerabilities** — vulnerabilities in third-party packages. Fix by upgrading the dep.');
    L.push('');
    L.push(`**Code findings:** ${s.critical}C ${s.high}H ${s.medium}M ${s.low}L (${s.total} total)`);
    if (d.tool) {
        L.push(`**Dependency vulns:** ${d.critical}C ${d.high}H ${d.medium}M ${d.low}L (${d.total} total, via ${d.tool})`);
        L.push('');
        L.push(`**Combined signals:** ${s.total + d.total} (${s.total} code + ${d.total} dependency)`);
    }
    else {
        L.push('**Dependency vulns:** no audit data');
        L.push('');
        L.push(`**Combined signals:** ${s.total} (code only)`);
    }
    L.push('');
    L.push('---');
    L.push('');
    // Ranked actions
    L.push('## Recommended Actions');
    L.push('');
    if (detailed.actions.length === 0) {
        L.push('No security findings — nothing to remediate.');
    }
    else {
        L.push('Actions are ranked by projected score improvement.');
        L.push('');
        L.push('| # | Action | Score Δ | Projected |');
        L.push('|---|--------|--------:|----------:|');
        detailed.actions.forEach((a, i) => {
            L.push(`| ${i + 1} | ${a.title} | +${a.scoreDelta} | ${a.projectedScore}/100 |`);
        });
        L.push('');
        for (const a of detailed.actions) {
            L.push(`### ${a.title} (+${a.scoreDelta})`);
            L.push('');
            L.push(`- **ID:** \`${a.id}\``);
            L.push(`- **Baseline:** ${a.baselineScore}/100`);
            L.push(`- **Projected:** ${a.projectedScore}/100`);
            if (a.rationale)
                L.push(`- **Why:** ${a.rationale}`);
            if (a.evidence.length) {
                L.push('- **Evidence:**');
                for (const e of a.evidence.slice(0, 20)) {
                    const loc = e.line ? `:${e.line}` : '';
                    L.push(`  - \`${e.file}${loc}\` — ${e.message || e.rule}`);
                }
                if (a.evidence.length > 20) {
                    L.push(`  - … and ${a.evidence.length - 20} more`);
                }
            }
            L.push('');
        }
    }
    L.push('---');
    L.push('');
    // Full findings inventory
    L.push('## Findings Inventory');
    L.push('');
    const sorted = [...detailed.findings].sort((a, b) => SEV_ORDER[a.severity] - SEV_ORDER[b.severity] || a.file.localeCompare(b.file));
    if (sorted.length === 0) {
        L.push('No code findings.');
    }
    else if (detailed.graphContext) {
        const gc = detailed.graphContext;
        L.push((0, finding_context_1.graphContextProvenanceLine)(gc));
        L.push('');
        L.push('| Severity | Rule | File:Line | Tool | CWE | Graph context |');
        L.push('|----------|------|-----------|------|-----|----------------|');
        for (const f of sorted) {
            const ctx = gc.contexts[(0, finding_context_1.locationKey)(f.file, f.line)];
            L.push(`| ${f.severity.toUpperCase()} | \`${f.rule}\` | \`${f.file}${f.line ? ':' + f.line : ''}\` | ${f.tool} | ${f.cwe || '—'} | ${(0, finding_context_1.formatGraphContextCell)(ctx)} |`);
        }
    }
    else {
        L.push('| Severity | Rule | File:Line | Tool | CWE |');
        L.push('|----------|------|-----------|------|-----|');
        for (const f of sorted) {
            L.push(`| ${f.severity.toUpperCase()} | \`${f.rule}\` | \`${f.file}${f.line ? ':' + f.line : ''}\` | ${f.tool} | ${f.cwe || '—'} |`);
        }
    }
    L.push('');
    L.push('---');
    L.push('');
    // Dependencies
    if (d.tool) {
        L.push('## Dependency Vulnerabilities');
        L.push('');
        L.push(`Tool: ${d.tool}`);
        L.push('');
        L.push('| Severity | Count |');
        L.push('|----------|------:|');
        L.push(`| Critical | ${d.critical} |`);
        L.push(`| High     | ${d.high} |`);
        L.push(`| Medium   | ${d.medium} |`);
        L.push(`| Low      | ${d.low} |`);
        L.push(`| **Total** | **${d.total}** |`);
        L.push('');
        if (d.findings.length > 0) {
            // Per-advisory inventory. Sorted by composite riskScore when
            // available (primary triage key), falling back to severity + package
            // for findings where CVSS was missing. Highest risk first.
            const sortedDeps = [...d.findings].sort((a, b) => {
                const ra = a.riskScore ?? -1;
                const rb = b.riskScore ?? -1;
                if (ra !== rb)
                    return rb - ra;
                return (SEV_ORDER[a.severity] - SEV_ORDER[b.severity] ||
                    a.package.localeCompare(b.package) ||
                    a.id.localeCompare(b.id));
            });
            L.push(`Per-advisory detail (${sortedDeps.length} findings):`);
            L.push('');
            L.push('| Risk | Severity | KEV | Reach | ID | Package | Installed | Fixed | CVSS | EPSS | Tool |');
            L.push('|-----:|----------|:---:|:-----:|----|---------|-----------|-------|-----:|-----:|------|');
            for (const f of sortedDeps) {
                const cvss = f.cvssScore !== undefined ? f.cvssScore.toFixed(1) : '—';
                const epss = typeof f.epssScore === 'number' ? `${(f.epssScore * 100).toFixed(2)}%` : '—';
                const kev = f.kev ? '⚠' : '';
                const reach = f.reachable === true ? '✓' : f.reachable === false ? '·' : '';
                // Composite risk (0–100). Bold since it's the primary sort key;
                // dash when CVSS was missing (risk uncomputable).
                const risk = typeof f.riskScore === 'number' ? `**${f.riskScore.toFixed(0)}**` : '—';
                L.push(`| ${risk} | ${f.severity.toUpperCase()} | ${kev} | ${reach} | \`${f.id}\` | \`${f.package}\` | ${f.installedVersion ?? '—'} | ${f.fixedVersion ?? '—'} | ${cvss} | ${epss} | ${f.tool} |`);
            }
            L.push('');
        }
        L.push('---');
        L.push('');
    }
    L.push(`**Tools used:** ${detailed.toolsUsed.join(', ')}`);
    L.push(...(0, tools_unavailable_prose_1.renderToolsUnavailableLines)(detailed.toolsUnavailable));
    L.push(`**Analysis time:** ${elapsed}s`);
    L.push('');
    L.push('*Generated by [VyuhLabs DXKit](https://www.npmjs.com/package/@vyuhlabs/dxkit) — detailed mode*');
    return L.join('\n');
}
//# sourceMappingURL=detailed.js.map