import { checkFileSafety } from "../prompt/safety.js";
import { resolvePathUnderWorkspace } from "./tool-paths.js";
import { evaluateFilePolicy } from "../sandbox/exec-policy.js";
import { fuzzyFindText, generateDiffString, normalizeForFuzzyMatch, normalizeToLF, restoreLineEndings, stripBom } from "./edit-diff.js";
import { readFile, stat, writeFile } from "fs/promises";
import { Type } from "@sinclair/typebox";
//#region src/agent/tools/edit.ts
const MAX_FILE_SIZE = 10 * 1024 * 1024;
const EditFileSchema = Type.Object({
	path: Type.String({ description: "File path to edit" }),
	oldText: Type.String({ description: "Text to replace" }),
	newText: Type.String({ description: "Replacement text" })
});
function createEditFileTool(workspace) {
	return {
		name: "edit_file",
		description: "Edit file by replacing text. Relative paths are under the current agent workspace.",
		parameters: EditFileSchema,
		label: "✏️ Edit",
		async execute(_toolCallId, params, _signal) {
			try {
				const p = params;
				const safety = checkFileSafety("write", p.path);
				if (!safety.allowed) return {
					content: [{
						type: "text",
						text: `🚫 ${safety.message}`
					}],
					details: {}
				};
				const pathPolicy = evaluateFilePolicy({
					operation: "edit",
					path: p.path,
					workspaceRoot: workspace
				});
				if (!pathPolicy.allowed) return {
					content: [{
						type: "text",
						text: `🚫 Sandbox: ${pathPolicy.reason}`
					}],
					details: {}
				};
				const normalized = resolvePathUnderWorkspace(p.path, workspace);
				if ((await stat(normalized)).size > MAX_FILE_SIZE) return {
					content: [{
						type: "text",
						text: `🚫 File too large`
					}],
					details: {}
				};
				const rawContent = await readFile(normalized, "utf-8");
				const content = stripBom(rawContent);
				const lineEnding = detectLineEnding(rawContent);
				const normalizedContent = normalizeToLF(content);
				const normalizedOldText = normalizeToLF(p.oldText);
				const normalizedNewText = normalizeToLF(p.newText);
				const matchResult = fuzzyFindText(normalizedContent, normalizedOldText);
				if (!matchResult.found) return {
					content: [{
						type: "text",
						text: `Error: oldText not found`
					}],
					details: {}
				};
				const fuzzyContent = normalizeForFuzzyMatch(normalizedContent);
				const fuzzyOldText = normalizeForFuzzyMatch(normalizedOldText);
				const occurrences = fuzzyContent.split(fuzzyOldText).length - 1;
				if (occurrences > 1) return {
					content: [{
						type: "text",
						text: `Error: ${occurrences} occurrences found, text must be unique`
					}],
					details: {}
				};
				const baseContent = matchResult.contentForReplacement;
				const finalContent = restoreLineEndings(baseContent.substring(0, matchResult.index) + normalizedNewText + baseContent.substring(matchResult.index + matchResult.matchLength), lineEnding);
				const originalWithReplacement = restoreLineEndings(baseContent, lineEnding);
				if (originalWithReplacement === finalContent) return {
					content: [{
						type: "text",
						text: `Error: No changes`
					}],
					details: {}
				};
				const diffResult = generateDiffString(originalWithReplacement, finalContent, normalized);
				await writeFile(normalized, finalContent, "utf-8");
				return {
					content: [{
						type: "text",
						text: `File edited: ${normalized}`
					}],
					details: {
						diff: diffResult,
						fuzzyMatchUsed: matchResult.usedFuzzyMatch
					}
				};
			} catch (error) {
				return {
					content: [{
						type: "text",
						text: `Error: ${error instanceof Error ? error.message : String(error)}`
					}],
					details: {}
				};
			}
		}
	};
}
const editFileTool = createEditFileTool(process.cwd());
function detectLineEnding(content) {
	const crlfIdx = content.indexOf("\r\n");
	const lfIdx = content.indexOf("\n");
	if (lfIdx === -1) return "\n";
	if (crlfIdx === -1) return "\n";
	return crlfIdx < lfIdx ? "\r\n" : "\n";
}
//#endregion
export { createEditFileTool, editFileTool };

//# sourceMappingURL=edit.js.map