import { minimatchFilter } from "../../../util/minimatch.js";
import { logger } from "../../../logger/index.js";
import { scm } from "../../platform/scm.js";
import { readFileAsXmlDocument } from "./util.js";
import { isNonEmptyString } from "@sindresorhus/is";
import upath from "upath";
import { Graph, hasCycle } from "graph-data-structure";

//#region lib/modules/manager/nuget/package-tree.ts
const GLOBAL_JSON = "global.json";
const NUGET_CENTRAL_FILE = "Directory.Packages.props";
const MSBUILD_CENTRAL_FILE = "Packages.props";
/**
* Get all leaf package files of ancestry that depend on packageFileName.
*/
async function getDependentPackageFiles(packageFileName, isCentralManagement = false, isGlobalJson = false) {
	const packageFiles = await getAllPackageFiles();
	const graph = new Graph();
	if (isCentralManagement) graph.addNode(packageFileName);
	if (isGlobalJson) graph.addNode(GLOBAL_JSON);
	const parentDir = packageFileName === NUGET_CENTRAL_FILE || packageFileName === MSBUILD_CENTRAL_FILE || packageFileName === GLOBAL_JSON ? "" : upath.dirname(packageFileName);
	for (const f of packageFiles) {
		graph.addNode(f);
		if ((isCentralManagement || isGlobalJson) && upath.dirname(f).startsWith(parentDir)) graph.addEdge(packageFileName, f);
	}
	for (const f of packageFiles) {
		const doc = await readFileAsXmlDocument(f);
		if (!doc) continue;
		const normalizedRelativeProjectReferences = doc.childrenNamed("ItemGroup").map((ig) => ig.childrenNamed("ProjectReference")).flat().map((pf) => pf.attr.Include).filter(isNonEmptyString).map((a) => upath.normalize(a)).map((r) => reframeRelativePathToRootOfRepo(f, r));
		for (const ref of normalizedRelativeProjectReferences) graph.addEdge(ref, f);
		if (hasCycle(graph)) throw new Error("Circular reference detected in NuGet package files");
	}
	const deps = /* @__PURE__ */ new Map();
	recursivelyGetDependentPackageFiles(packageFileName, graph, deps);
	if (isCentralManagement || isGlobalJson) deps.delete(packageFileName);
	return Array.from(deps).map(([name, isLeaf]) => ({
		name,
		isLeaf
	}));
}
/**
* Traverse graph and find dependent package files at any level of ancestry
*/
function recursivelyGetDependentPackageFiles(packageFileName, graph, deps) {
	if (deps.has(packageFileName)) return;
	const dependents = graph.adjacent(packageFileName);
	if (!dependents || dependents.size === 0) {
		deps.set(packageFileName, true);
		return;
	}
	deps.set(packageFileName, false);
	for (const dep of dependents) recursivelyGetDependentPackageFiles(dep, graph, deps);
}
/**
* Take the path relative from a project file, and make it relative from the root of the repo
*/
function reframeRelativePathToRootOfRepo(dependentProjectRelativePath, projectReference) {
	const virtualRepoRoot = "/";
	const absoluteDependentProjectPath = upath.resolve(virtualRepoRoot, dependentProjectRelativePath);
	const absoluteProjectReferencePath = upath.resolve(upath.dirname(absoluteDependentProjectPath), projectReference);
	return upath.relative(virtualRepoRoot, absoluteProjectReferencePath);
}
/**
* Get a list of package files in localDir
*/
async function getAllPackageFiles() {
	const filteredPackageFiles = (await scm.getFileList()).filter(minimatchFilter("*.{cs,vb,fs}proj", {
		matchBase: true,
		nocase: true
	}));
	logger.trace({ filteredPackageFiles }, "Found package files");
	return filteredPackageFiles;
}

//#endregion
export { GLOBAL_JSON, MSBUILD_CENTRAL_FILE, NUGET_CENTRAL_FILE, getDependentPackageFiles };
//# sourceMappingURL=package-tree.js.map