import { NO_VULNERABILITY_ALERTS } from "../../../constants/error-messages.js";
import { escapeRegExp, regEx } from "../../../util/regex.js";
import { titleCase } from "../../../util/string.js";
import { logger } from "../../../logger/index.js";
import { getHighestVulnerabilitySeverity } from "../../../util/vulnerability/utils.js";
import { get } from "../../../modules/versioning/index.js";
import { MavenDatasource } from "../../../modules/datasource/maven/index.js";
import { GithubTagsDatasource } from "../../../modules/datasource/github-tags/index.js";
import { NugetDatasource } from "../../../modules/datasource/nuget/index.js";
import { getDefaultVersioning } from "../../../modules/datasource/common.js";
import { platform } from "../../../modules/platform/index.js";
import { sanitizeMarkdown } from "../../../util/markdown.js";
import { githubEcosystemToDatasource } from "../../../util/vulnerability/ecosystem.js";
import is from "@sindresorhus/is";
//#region lib/workers/repository/init/vulnerability.ts
async function detectVulnerabilityAlerts(input) {
	if (!input?.vulnerabilityAlerts) return input;
	if (input.vulnerabilityAlerts.enabled === false) {
		logger.debug("Vulnerability alerts are disabled");
		return input;
	}
	const alerts = await platform.getVulnerabilityAlerts?.();
	if (!alerts?.length) {
		logger.debug("No vulnerability alerts found");
		if (input.vulnerabilityAlertsOnly) throw new Error(NO_VULNERABILITY_ALERTS);
		return input;
	}
	const config = { ...input };
	const combinedAlerts = {};
	for (const alert of alerts) try {
		if (alert.dismissed_reason) continue;
		if (!alert.security_vulnerability?.first_patched_version) {
			logger.debug({ alert }, "Vulnerability alert has no firstPatchedVersion - skipping");
			continue;
		}
		const ecosystem = alert.security_vulnerability.package.ecosystem;
		const datasources = githubEcosystemToDatasource[ecosystem];
		const depName = alert.security_vulnerability.package.name;
		const firstPatchedVersion = alert.security_vulnerability.first_patched_version.identifier;
		const advisory = alert.security_advisory;
		combinedAlerts[ecosystem] ??= {};
		combinedAlerts[ecosystem][depName] ??= { advisories: [] };
		const alertDetails = combinedAlerts[ecosystem][depName];
		alertDetails.advisories.push(advisory);
		alertDetails.severity = getHighestVulnerabilitySeverity({ vulnerabilitySeverity: alertDetails.severity }, { vulnerabilitySeverity: alert.security_vulnerability.severity });
		const versioningApi = get(getDefaultVersioning(datasources[0]));
		if (versioningApi.isVersion(firstPatchedVersion)) {
			if (!alertDetails.firstPatchedVersion || versioningApi.isGreaterThan(firstPatchedVersion, alertDetails.firstPatchedVersion)) alertDetails.firstPatchedVersion = firstPatchedVersion;
		} else logger.debug(`Invalid firstPatchedVersion: ${firstPatchedVersion}`);
	} catch (err) {
		logger.warn({ err }, "Error parsing vulnerability alert");
	}
	const alertPackageRules = [];
	config.remediations = {};
	for (const [ecosystem, dependencies] of Object.entries(combinedAlerts)) {
		const matchDatasources = githubEcosystemToDatasource[ecosystem];
		const primaryDatasource = matchDatasources[0];
		for (const [depName, val] of Object.entries(dependencies)) {
			if (!val.firstPatchedVersion) continue;
			let prBodyNotes = [];
			try {
				prBodyNotes = val.advisories.flatMap((advisory) => generatePrBodyNotes(advisory));
			} catch (err) 			/* v8 ignore next -- defensive: note generation from already-parsed advisories does not throw in specs */ {
				logger.warn({ err }, "Error generating vulnerability PR notes");
			}
			let matchRule = {
				matchDatasources,
				matchPackageNames: [depName]
			};
			let matchCurrentVersion = `< ${val.firstPatchedVersion}`;
			if (primaryDatasource === MavenDatasource.id || primaryDatasource === NugetDatasource.id) matchCurrentVersion = `(,${val.firstPatchedVersion})`;
			else if (primaryDatasource === GithubTagsDatasource.id) matchCurrentVersion = `!/^${escapeRegExp(val.firstPatchedVersion)}$/`;
			matchRule = {
				...matchRule,
				matchCurrentVersion,
				vulnerabilityFixVersion: val.firstPatchedVersion,
				vulnerabilitySeverity: val.severity,
				prBodyNotes,
				isVulnerabilityAlert: true,
				force: { ...config.vulnerabilityAlerts }
			};
			alertPackageRules.push(matchRule);
		}
	}
	logger.debug({ alertPackageRules }, "alert package rules");
	config.packageRules = (config.packageRules ?? []).concat(alertPackageRules);
	return config;
}
function generatePrBodyNotes(advisory) {
	const aliases = advisory.identifiers.map((id) => id.value).sort().map((id) => {
		if (id.startsWith("CVE-")) return `[${id}](https://nvd.nist.gov/vuln/detail/${id})`;
		if (id.startsWith("GHSA-")) return `[${id}](https://github.com/advisories/${id})`;
		return id;
	});
	let content = "\n\n---\n\n### ";
	content += `${advisory.summary}\n`;
	content += `${aliases.join(" / ")}\n`;
	content += `\n<details>\n<summary>More information</summary>\n`;
	const details = advisory.description.replace(regEx(/^#{1,4} /gm), "##### ");
	content += `#### Details\n${details}\n`;
	content += "#### Severity\n";
	const { cvss_v4, cvss_v3 } = advisory.cvss_severities ?? {};
	const cvss = cvss_v4?.vector_string ? cvss_v4 : cvss_v3;
	if (is.number(cvss?.score) && cvss?.vector_string) {
		content += `- CVSS Score: ${cvss.score.toFixed(1)} / 10 (${titleCase(advisory.severity)})\n`;
		content += `- Vector String: \`${cvss.vector_string}\`\n`;
	} else content += `${titleCase(advisory.severity)}\n`;
	content += `\n#### References\n${advisory.references?.map((ref) => `- [${ref.url}](${ref.url})`).join("\n") ?? "No references."}`;
	content += `\n\nThis data is provided by the [GitHub Advisory Database](https://github.com/advisories/${advisory.ghsa_id}) ([CC-BY 4.0](https://github.com/github/advisory-database/blob/main/LICENSE.md)).\n`;
	content += `</details>`;
	return [sanitizeMarkdown(content)];
}
//#endregion
export { detectVulnerabilityAlerts };

//# sourceMappingURL=vulnerability.js.map