"use strict";
/* Socket Lib - Built with rolldown */
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
const require_primordials_buffer = require('../primordials/buffer.js');
const require_primordials_string = require('../primordials/string.js');
const require_paths_normalize = require('../paths/normalize.js');
const require_primordials_array = require('../primordials/array.js');
const require_primordials_map_set = require('../primordials/map-set.js');
const require_node_path = require('../node/path.js');
const require_primordials_date = require('../primordials/date.js');
const require_primordials_object = require('../primordials/object.js');
const require_primordials_json = require('../primordials/json.js');
const require_bin_which = require('../bin/which.js');
const require_ansi_strip = require('../ansi/strip.js');
const require_process_spawn_child = require('../process/spawn/child.js');
const require_debug_output = require('../debug/output.js');
const require_globs_matcher = require('../globs/matcher.js');
const require_git_repo = require('./repo.js');

//#region src/git/_internal.ts
/**
* @file Cross-leaf diff machinery for `git/*`. Owns the LRU+TTL git-diff cache,
*   the spawn-args builder, the porcelain-output parser, and the async/sync
*   `innerDiff` runners. Public-surface leaves (`changed.ts`, `staged.ts`,
*   `unstaged.ts`) call into these helpers; nothing else should.
*/
const gitDiffCache = new require_primordials_map_set.MapCtor();
const GIT_CACHE_MAX_SIZE = 100;
const GIT_CACHE_TTL_MS = 2e3;
let _gitPath;
function getCachedGitDiff(key) {
	const entry = gitDiffCache.get(key);
	if (!entry) return;
	if (require_primordials_date.DateNow() >= entry.expiresAt) {
		gitDiffCache.delete(key);
		return;
	}
	gitDiffCache.delete(key);
	gitDiffCache.set(key, entry);
	return entry.result;
}
/**
* Get spawn arguments for different git diff operations.
*
* Prepares argument arrays for `spawn()`/`spawnSync()` calls that retrieve: -
* `all`: All changed files (staged, unstaged, untracked) via `git status
* --porcelain` - `unstaged`: Unstaged modifications via `git diff --name-only`
* - `staged`: Staged changes via `git diff --cached --name-only`
*
* Automatically resolves symlinks in the provided `cwd` and enables shell mode
* on Windows for proper command execution.
*
* @param cwd - Working directory for git operations, defaults to
*   `process.cwd()`.
*
* @returns Object containing spawn arguments for all, unstaged, and staged
*   operations.
*/
function getGitDiffSpawnArgs(cwd) {
	const resolvedCwd = cwd ? require_git_repo.getCachedRealpath(cwd) : require_git_repo.getCwd();
	return {
		all: [
			getGitPath(),
			["status", "--porcelain"],
			{ cwd: resolvedCwd }
		],
		unstaged: [
			getGitPath(),
			["diff", "--name-only"],
			{ cwd: resolvedCwd }
		],
		staged: [
			getGitPath(),
			[
				"diff",
				"--cached",
				"--name-only"
			],
			{ cwd: resolvedCwd }
		]
	};
}
/**
* Get the git executable path.
*
* Resolves the git binary path via PATH on first call and caches it. Falls back
* to 'git' if not found in PATH.
*
* @example
*   ;```typescript
*   const git = getGitPath()
*   // => '/usr/bin/git' or 'git' if not found
*   ```
*
* @returns The git executable path (resolved from PATH on first call).
*/
function getGitPath() {
	/* c8 ignore start */
	if (_gitPath === void 0) {
		const resolved = require_bin_which.whichSync("git", { nothrow: true });
		_gitPath = typeof resolved === "string" ? resolved : "git";
	}
	/* c8 ignore stop */
	return _gitPath;
}
/**
* Execute git diff command asynchronously and parse results.
*
* Internal helper for async git operations. Handles caching, command execution,
* and result parsing. Returns empty array on git command failure.
*
* @param args - Spawn arguments tuple `[command, args, options]`.
* @param options - Git diff options for caching and parsing.
*
* @returns Promise resolving to array of file paths.
*/
async function innerDiff(args, options) {
	const { cache = true, ...parseOptions } = {
		__proto__: null,
		...options
	};
	const cacheKey = cache ? stableKey({
		args,
		parseOptions
	}) : void 0;
	if (cache && cacheKey) {
		const result = getCachedGitDiff(cacheKey);
		if (result) return result;
	}
	let result;
	try {
		const spawnResult = await require_process_spawn_child.spawn(args[0], args[1], {
			...args[2],
			stdioString: false
		});
		/* c8 ignore stop */
		result = parseGitDiffStdout(require_primordials_buffer.BufferIsBuffer(spawnResult.stdout) ? spawnResult.stdout.toString("utf8") : 
		/* c8 ignore next */
String(spawnResult.stdout), parseOptions, typeof args[2]["cwd"] === "string" ? args[2]["cwd"] : void 0);
	} catch (e) {
		require_debug_output.debugNs("git", `Git command failed (${args[0]} ${args[1].join(" ")}): ${e.message}`);
		return [];
	}
	if (cache && cacheKey) setCachedGitDiff(cacheKey, result);
	return result;
}
/**
* Execute git diff command synchronously and parse results.
*
* Internal helper for sync git operations. Handles caching, command execution,
* and result parsing. Returns empty array on git command failure.
*
* @param args - Spawn arguments tuple `[command, args, options]`.
* @param options - Git diff options for caching and parsing.
*
* @returns Array of file paths.
*/
function innerDiffSync(args, options) {
	const { cache = true, ...parseOptions } = {
		__proto__: null,
		...options
	};
	const cacheKey = cache ? stableKey({
		args,
		parseOptions
	}) : void 0;
	if (cache && cacheKey) {
		const result = getCachedGitDiff(cacheKey);
		if (result) return result;
	}
	let result;
	try {
		const spawnResult = require_process_spawn_child.spawnSync(args[0], args[1], {
			...args[2],
			stdioString: false
		});
		/* c8 ignore stop */
		result = parseGitDiffStdout(require_primordials_buffer.BufferIsBuffer(spawnResult.stdout) ? spawnResult.stdout.toString("utf8") : 
		/* c8 ignore next */
String(spawnResult.stdout), parseOptions, typeof args[2]["cwd"] === "string" ? args[2]["cwd"] : void 0);
	} catch (e) {
		require_debug_output.debugNs("git", `Git command failed (${args[0]} ${args[1].join(" ")}): ${e.message}`);
		return [];
	}
	if (cache && cacheKey) setCachedGitDiff(cacheKey, result);
	return result;
}
/**
* Parse git diff stdout output into file path array.
*
* Internal helper that processes raw git command output by: 1. Finding git
* repository root from spawn cwd 2. Stripping ANSI codes and splitting into
* lines 3. Parsing porcelain format status codes if requested 4. Normalizing
* and optionally making paths absolute 5. Filtering paths based on cwd and glob
* options.
*
* Git always returns paths relative to the repository root, regardless of where
* the command was executed. This function handles the path resolution correctly
* by finding the repo root and adjusting paths accordingly.
*
* @param stdout - Raw stdout from git command.
* @param options - Git diff options for path processing.
* @param spawnCwd - Working directory where git command was executed.
*
* @returns Array of processed file paths.
*/
function parseGitDiffStdout(stdout, options, spawnCwd) {
	/* c8 ignore next */
	const defaultRoot = spawnCwd ? require_git_repo.findGitRoot(spawnCwd) : require_git_repo.getCwd();
	const { absolute = false, cwd: cwdOption = defaultRoot, porcelain = false, ...matcherOptions } = {
		__proto__: null,
		...options
	};
	const path = /* @__PURE__ */ require_node_path.getNodePath();
	const cwd = cwdOption === defaultRoot ? defaultRoot : require_git_repo.getCachedRealpath(cwdOption);
	const rootPath = defaultRoot;
	let rawFiles = stdout ? (/* @__PURE__ */ require_ansi_strip.stripAnsi(stdout)).split(/\r?\n/).map((line) => line.trimEnd()).filter((line) => line) : [];
	if (porcelain) rawFiles = rawFiles.map((line) => {
		/* c8 ignore next */
		return line.length > 3 ? require_primordials_string.StringPrototypeSubstring(line, 3) : line;
	});
	const files = absolute ? rawFiles.map((relPath) => /* @__PURE__ */ require_paths_normalize.normalizePath(path.join(rootPath, relPath))) : rawFiles.map((relPath) => /* @__PURE__ */ require_paths_normalize.normalizePath(relPath));
	if (cwd === rootPath) return files;
	const matcher = /* @__PURE__ */ require_globs_matcher.getGlobMatcher([`${/* @__PURE__ */ require_paths_normalize.normalizePath(path.relative(rootPath, cwd))}/**`], {
		...matcherOptions,
		absolute,
		cwd: rootPath
	});
	const filtered = [];
	for (const filepath of files) if (matcher(filepath)) filtered.push(filepath);
	return filtered;
}
function setCachedGitDiff(key, result) {
	/* c8 ignore start */
	if (gitDiffCache.size >= 100) {
		const oldest = gitDiffCache.keys().next().value;
		if (oldest !== void 0) gitDiffCache.delete(oldest);
	}
	/* c8 ignore stop */
	gitDiffCache.set(key, {
		expiresAt: Date.now() + GIT_CACHE_TTL_MS,
		result
	});
}
/**
* Build a stable cache key that is insensitive to object-property insertion
* order, so callers passing the same options with different shapes hit the same
* cache slot.
*/
function stableKey(value) {
	return require_primordials_json.JSONStringify(value, (_key, val) => {
		if (val && typeof val === "object" && !require_primordials_array.ArrayIsArray(val)) {
			const sorted = {};
			for (const k of require_primordials_object.ObjectKeys(val).sort()) sorted[k] = val[k];
			return sorted;
		}
		return val;
	});
}

//#endregion
exports.GIT_CACHE_MAX_SIZE = GIT_CACHE_MAX_SIZE;
exports.GIT_CACHE_TTL_MS = GIT_CACHE_TTL_MS;
exports.getCachedGitDiff = getCachedGitDiff;
exports.getGitDiffSpawnArgs = getGitDiffSpawnArgs;
exports.getGitPath = getGitPath;
exports.gitDiffCache = gitDiffCache;
exports.innerDiff = innerDiff;
exports.innerDiffSync = innerDiffSync;
exports.parseGitDiffStdout = parseGitDiffStdout;
exports.setCachedGitDiff = setCachedGitDiff;
exports.stableKey = stableKey;