import { regEx } from "../../../util/regex.js";
import { matchRegexOrGlob } from "../../../util/string-match.js";
import { logger } from "../../../logger/index.js";
import { ensureCacheDir, localPathExists, readLocalFile, writeLocalFile } from "../../../util/fs/index.js";
import { exec } from "../../../util/exec/index.js";
import { PNPM_CACHE_DIR, PNPM_STORE_DIR } from "./constants.js";
import { getNodeToolConstraint } from "./post-update/node-version.js";
import { processHostRules } from "./post-update/rules.js";
import { getNpmrcContent, resetNpmrcContent, updateNpmrcContent } from "./utils.js";
import { lazyLoadPackageJson } from "./post-update/utils.js";
import { isEmptyArray, isNonEmptyObject, isString } from "@sindresorhus/is";
import upath from "upath";
import { isScalar, isSeq, parseDocument } from "yaml";

//#region lib/modules/manager/npm/artifacts.ts
const versionWithHashRegString = "^(?<version>.*)\\+(?<hash>.*)";
async function updateArtifacts(updateArtifactsConfig) {
	logger.debug(`npm.updateArtifacts(${updateArtifactsConfig.packageFileName})`);
	let res = [];
	res.push(await handlePackageManagerUpdates(updateArtifactsConfig) ?? {});
	res.push(await updatePnpmWorkspace(updateArtifactsConfig) ?? {});
	res = res.filter(isNonEmptyObject);
	if (res.length === 0) return null;
	return res;
}
async function handlePackageManagerUpdates(updateArtifactsConfig) {
	const { packageFileName, config, updatedDeps, newPackageFileContent: existingPackageFileContent } = updateArtifactsConfig;
	const packageManagerUpdate = updatedDeps.find((dep) => dep.depType === "packageManager");
	if (!packageManagerUpdate) {
		logger.debug("No packageManager updates - returning null");
		return null;
	}
	const { currentValue, depName, newVersion } = packageManagerUpdate;
	if (!currentValue || !regEx(versionWithHashRegString).test(currentValue)) return null;
	await writeLocalFile(packageFileName, existingPackageFileContent);
	const pkgFileDir = upath.dirname(packageFileName);
	const { additionalNpmrcContent } = processHostRules();
	const npmrcContent = await getNpmrcContent(pkgFileDir);
	const lazyPkgJson = lazyLoadPackageJson(pkgFileDir);
	const cmd = `corepack use ${depName}@${newVersion}`;
	const nodeConstraints = await getNodeToolConstraint(config, updatedDeps, pkgFileDir, lazyPkgJson);
	const pnpmConfigCacheDir = await ensureCacheDir(PNPM_CACHE_DIR);
	const pnpmConfigStoreDir = await ensureCacheDir(PNPM_STORE_DIR);
	const execOptions = {
		cwdFile: packageFileName,
		extraEnv: {
			npm_config_cache_dir: pnpmConfigCacheDir,
			npm_config_store_dir: pnpmConfigStoreDir,
			pnpm_config_cache_dir: pnpmConfigCacheDir,
			pnpm_config_store_dir: pnpmConfigStoreDir
		},
		toolConstraints: [nodeConstraints, {
			toolName: "corepack",
			constraint: config.constraints?.corepack
		}],
		docker: {}
	};
	await updateNpmrcContent(pkgFileDir, npmrcContent, additionalNpmrcContent);
	try {
		await exec(cmd, execOptions);
		await resetNpmrcContent(pkgFileDir, npmrcContent);
		const newPackageFileContent = await readLocalFile(packageFileName, "utf8");
		if (!newPackageFileContent || existingPackageFileContent === newPackageFileContent) return null;
		logger.debug("Returning updated package.json");
		return { file: {
			type: "addition",
			path: packageFileName,
			contents: newPackageFileContent
		} };
	} catch (err) {
		logger.warn({ err }, "Error updating package.json");
		await resetNpmrcContent(pkgFileDir, npmrcContent);
		return { artifactError: {
			fileName: packageFileName,
			stderr: err.message
		} };
	}
}
/**
* Update the minimumReleaseAgeExclude setting in pnpm-workspace.yaml if needed
*/
async function updatePnpmWorkspace(updateArtifactsConfig) {
	const upgrades = updateArtifactsConfig.updatedDeps.filter((u) => u.isVulnerabilityAlert);
	if (isEmptyArray(upgrades)) return null;
	const pnpmShrinkwrap = upgrades[0].managerData?.pnpmShrinkwrap;
	if (!isString(pnpmShrinkwrap)) {
		logger.debug("No pnpm shrinkwrap found, not attempting to update pnpm-workspace.yaml");
		return null;
	}
	const lockFileDir = upath.dirname(pnpmShrinkwrap);
	const pnpmWorkspaceFilePath = upath.join(lockFileDir, "pnpm-workspace.yaml");
	if (!await localPathExists(pnpmWorkspaceFilePath)) return null;
	const doc = parseDocument(await readLocalFile(pnpmWorkspaceFilePath, "utf8"));
	if (!doc.get("minimumReleaseAge")) return null;
	let updated = false;
	for (const upgrade of upgrades) {
		let excludeNode = doc.getIn(["minimumReleaseAgeExclude"]);
		const newVersion = upgrade.newVersion ?? upgrade.newValue;
		/* v8 ignore if -- should not happen, adding for type narrowing*/
		if (excludeNode && !isSeq(excludeNode)) return null;
		if (!excludeNode) {
			logger.debug("Adding new exclude block");
			excludeNode = doc.createNode([]);
			const newItem = doc.createNode(`${upgrade.depName}@${newVersion}`);
			newItem.commentBefore = ` Renovate security update: ${upgrade.depName}@${newVersion}`;
			excludeNode.items.push(newItem);
			doc.set("minimumReleaseAgeExclude", excludeNode);
			updated = true;
			continue;
		}
		const { item: matchedItem, allExcluded } = getMatchedItem(upgrade.depName, excludeNode.items);
		if (allExcluded) continue;
		if (isScalar(matchedItem)) {
			if (excludeNode?.commentBefore?.includes(`${upgrade.depName}@`)) {
				if (!minimumReleaseAgeExcludeIncludesDepNameAndVersion(excludeNode.commentBefore, upgrade.depName, newVersion)) {
					excludeNode.commentBefore = excludeNode.commentBefore + ` || ${newVersion}`;
					updated = true;
				}
			} else if (matchedItem.commentBefore) {
				if (!minimumReleaseAgeExcludeIncludesDepNameAndVersion(matchedItem.commentBefore, upgrade.depName, newVersion)) {
					matchedItem.commentBefore = matchedItem.commentBefore + ` || ${newVersion}`;
					updated = true;
				}
			} else {
				matchedItem.commentBefore = ` Renovate security update: ${upgrade.depName}@${newVersion}`;
				updated = true;
			}
			if (!minimumReleaseAgeExcludeIncludesDepNameAndVersion(matchedItem.value, upgrade.depName, newVersion)) {
				matchedItem.value = matchedItem.value + ` || ${newVersion}`;
				updated = true;
			}
		} else {
			const newItem = doc.createNode(`${upgrade.depName}@${newVersion}`);
			newItem.commentBefore = ` Renovate security update: ${upgrade.depName}@${newVersion}`;
			excludeNode.items.push(newItem);
			updated = true;
		}
	}
	if (!updated) return null;
	const newContent = doc.toString();
	await writeLocalFile(pnpmWorkspaceFilePath, newContent);
	return { file: {
		type: "addition",
		path: pnpmWorkspaceFilePath,
		contents: newContent
	} };
}
function getMatchedItem(depName, items) {
	for (const item of items) {
		/* v8 ignore if -- should not happen */
		if (!isScalar(item) || !isString(item.value)) continue;
		if (item.value.startsWith(`${depName}@`)) return {
			allExcluded: false,
			item
		};
		if (item.value === depName || matchRegexOrGlob(depName, item.value)) return {
			allExcluded: true,
			item
		};
	}
	return {
		item: null,
		allExcluded: false
	};
}
/** determine whether a comment or a list item contains the depName at a given newVersion */
function minimumReleaseAgeExcludeIncludesDepNameAndVersion(line, depName, newVersion) {
	if (line.includes(`${depName}@${newVersion}`)) return true;
	if (line.includes(`|| ${newVersion}`)) return true;
	return false;
}

//#endregion
export { updateArtifacts };
//# sourceMappingURL=artifacts.js.map