import { a as normalizeLowercaseStringOrEmpty } from "./string-coerce-DKw2K5wM.js";
import { n as resolveNodmixPackageRootSync } from "./nodmix-root-DFuWr6Ye.js";
import { n as resolveGitHeadPath } from "./git-root-B5CYl5JZ.js";
import { createRequire } from "node:module";
import { fileURLToPath } from "node:url";
import fs from "node:fs";
import path from "node:path";
//#region src/infra/git-commit.ts
const formatCommit = (value) => {
	if (!value) return null;
	const trimmed = value.trim();
	if (!trimmed) return null;
	const match = trimmed.match(/[0-9a-fA-F]{7,40}/);
	if (!match) return null;
	return normalizeLowercaseStringOrEmpty(match[0].slice(0, 7));
};
const cachedGitCommitBySearchDir = /* @__PURE__ */ new Map();
function isMissingPathError(error) {
	if (!(error instanceof Error)) return false;
	const code = error.code;
	return code === "ENOENT" || code === "ENOTDIR";
}
const resolveCommitSearchDir = (options) => {
	if (options.cwd) return path.resolve(options.cwd);
	if (options.moduleUrl) try {
		return path.dirname(fileURLToPath(options.moduleUrl));
	} catch {}
	return process.cwd();
};
/** Read at most `limit` bytes from a file to avoid unbounded reads. */
const safeReadFilePrefix = (filePath, limit = 256) => {
	const fd = fs.openSync(filePath, "r");
	try {
		const buf = Buffer.alloc(limit);
		const bytesRead = fs.readSync(fd, buf, 0, limit, 0);
		return buf.subarray(0, bytesRead).toString("utf-8");
	} finally {
		fs.closeSync(fd);
	}
};
const cacheGitCommit = (searchDir, commit) => {
	cachedGitCommitBySearchDir.set(searchDir, commit);
	return commit;
};
const clearCachedGitCommits = () => {
	cachedGitCommitBySearchDir.clear();
};
const resolveGitLookupDepth = (searchDir, packageRoot) => {
	if (!packageRoot) return;
	const relative = path.relative(packageRoot, searchDir);
	if (relative.startsWith("..") || path.isAbsolute(relative)) return;
	return (relative ? relative.split(path.sep).filter(Boolean).length : 0) + 1;
};
const readCommitFromGit = (searchDir, packageRoot) => {
	const headPath = resolveGitHeadPath(searchDir, { maxDepth: resolveGitLookupDepth(searchDir, packageRoot) });
	if (!headPath) return;
	const head = fs.readFileSync(headPath, "utf-8").trim();
	if (!head) return null;
	if (head.startsWith("ref:")) {
		const ref = head.replace(/^ref:\s*/i, "").trim();
		const refsBase = resolveGitRefsBase(headPath);
		const refPath = resolveRefPath(refsBase, ref);
		if (!refPath) return null;
		try {
			return formatCommit(safeReadFilePrefix(refPath).trim());
		} catch (error) {
			if (!isMissingPathError(error)) throw error;
		}
		return readCommitFromPackedRefs(refsBase, ref);
	}
	return formatCommit(head);
};
const resolveGitRefsBase = (headPath) => {
	const gitDir = path.dirname(headPath);
	try {
		const commonDir = safeReadFilePrefix(path.join(gitDir, "commondir")).trim();
		if (commonDir) return path.resolve(gitDir, commonDir);
	} catch (error) {
		if (!isMissingPathError(error)) throw error;
	}
	return gitDir;
};
const readCommitFromPackedRefs = (refsBase, ref) => {
	try {
		const packedRefs = fs.readFileSync(path.join(refsBase, "packed-refs"), "utf-8");
		for (const line of packedRefs.split("\n")) {
			if (!line || line.startsWith("#") || line.startsWith("^")) continue;
			const [commit, packedRef] = line.trim().split(/\s+/, 2);
			if (packedRef === ref) return formatCommit(commit);
		}
		return null;
	} catch (error) {
		if (!isMissingPathError(error)) throw error;
		return null;
	}
};
/** Safely resolve a git ref path, rejecting traversal attacks from a crafted HEAD file. */
const resolveRefPath = (refsBase, ref) => {
	if (!ref.startsWith("refs/")) return null;
	if (path.isAbsolute(ref)) return null;
	if (ref.split(/[/]/).includes("..")) return null;
	const resolved = path.resolve(refsBase, ref);
	const rel = path.relative(refsBase, resolved);
	if (!rel || rel.startsWith("..") || path.isAbsolute(rel)) return null;
	return resolved;
};
const readCommitFromPackageJson = () => {
	try {
		const pkg = createRequire(import.meta.url)("../../package.json");
		return formatCommit(pkg.gitHead ?? pkg.githead ?? null);
	} catch {
		return null;
	}
};
const readCommitFromBuildInfo = () => {
	try {
		const require = createRequire(import.meta.url);
		for (const candidate of ["../build-info.json", "./build-info.json"]) try {
			const formatted = formatCommit(require(candidate).commit ?? null);
			if (formatted) return formatted;
		} catch {}
		return null;
	} catch {
		return null;
	}
};
const resolveCommitHash = (options = {}) => {
	const env = options.env ?? process.env;
	const readers = options.readers ?? {};
	const readGitCommit = readers.readGitCommit ?? readCommitFromGit;
	const normalized = formatCommit(env.GIT_COMMIT?.trim() || env.GIT_SHA?.trim());
	if (normalized) return normalized;
	const searchDir = resolveCommitSearchDir(options);
	if (cachedGitCommitBySearchDir.has(searchDir)) return cachedGitCommitBySearchDir.get(searchDir) ?? null;
	const packageRoot = resolveNodmixPackageRootSync({
		cwd: options.cwd,
		moduleUrl: options.moduleUrl
	});
	try {
		const gitCommit = readGitCommit(searchDir, packageRoot);
		if (gitCommit !== void 0) return cacheGitCommit(searchDir, gitCommit);
	} catch {}
	const buildInfoCommit = readers.readBuildInfoCommit?.() ?? readCommitFromBuildInfo();
	if (buildInfoCommit) return cacheGitCommit(searchDir, buildInfoCommit);
	const pkgCommit = readers.readPackageJsonCommit?.() ?? readCommitFromPackageJson();
	if (pkgCommit) return cacheGitCommit(searchDir, pkgCommit);
	try {
		return cacheGitCommit(searchDir, readGitCommit(searchDir, packageRoot) ?? null);
	} catch {
		return cacheGitCommit(searchDir, null);
	}
};
const testing = { clearCachedGitCommits };
//#endregion
export { testing as n, resolveCommitHash as t };
