export interface ParsedFile {
	path: string;
	oldPath: string;
	newPath: string;
	status: "added" | "modified" | "deleted" | "renamed";
	additions: number;
	deletions: number;
	binary: boolean;
}

export function unquotePath(p: string): string {
	if (!p.startsWith('"')) return p;
	const inner = p.slice(1, -1);
	const bytes: number[] = [];
	let i = 0;
	const simpleEscapes: Record<string, number> = {
		"\\": 0x5c,
		'"': 0x22,
		n: 0x0a,
		t: 0x09,
		a: 0x07,
		b: 0x08,
	};
	while (i < inner.length) {
		if (inner[i] === "\\" && /^[0-7]{3}/.test(inner.slice(i + 1, i + 4))) {
			bytes.push(parseInt(inner.slice(i + 1, i + 4), 8));
			i += 4;
		} else if (inner[i] === "\\" && inner[i + 1] in simpleEscapes) {
			bytes.push(simpleEscapes[inner[i + 1]]);
			i += 2;
		} else {
			bytes.push(inner.charCodeAt(i));
			i++;
		}
	}
	return new TextDecoder("utf-8").decode(new Uint8Array(bytes));
}

export function parseDiff(diff: string): ParsedFile[] {
	if (!diff.trim()) return [];

	const results: ParsedFile[] = [];
	const lines = diff.split("\n");

	let current: Partial<ParsedFile> & { binary?: boolean } | null = null;

	const flush = () => {
		if (!current) return;
		const status = current.status ?? "modified";
		const path =
			status === "deleted"
				? current.oldPath || ""
				: current.newPath || current.oldPath || "";
		results.push({
			path,
			oldPath: current.oldPath ?? "",
			newPath: current.newPath ?? "",
			status,
			additions: current.additions ?? 0,
			deletions: current.deletions ?? 0,
			binary: current.binary ?? false,
		});
		current = null;
	};

	for (const line of lines) {
		if (line.startsWith("diff --git ")) {
			flush();
			// Initial parse — may be wrong for paths containing " b/"; overridden by ---/+++ lines below
			const match = line.match(/^diff --git a\/(.*) b\/(.*)$/);
			if (match) {
				current = {
					oldPath: match[1],
					newPath: match[2],
					status: "modified",
					additions: 0,
					deletions: 0,
				};
			}
			continue;
		}

		if (!current) continue;

		if (line.startsWith("new file mode")) {
			current.status = "added";
		} else if (line.startsWith("deleted file mode")) {
			current.status = "deleted";
		} else if (line.startsWith("rename from ")) {
			current.oldPath = line.slice("rename from ".length);
			current.status = "renamed";
		} else if (line.startsWith("rename to ")) {
			current.newPath = line.slice("rename to ".length);
		} else if (line.startsWith("--- ")) {
			const src = unquotePath(line.slice(4));
			if (src === "/dev/null") {
				current.oldPath = "";
			} else if (src.startsWith("a/")) {
				current.oldPath = src.slice(2);
			}
		} else if (line.startsWith("+++ ")) {
			const src = unquotePath(line.slice(4));
			if (src === "/dev/null") {
				current.newPath = "";
			} else if (src.startsWith("b/")) {
				current.newPath = src.slice(2);
			}
		} else if (
			line.startsWith("Binary files ") ||
			line.startsWith("GIT binary patch")
		) {
			current.binary = true;
		} else if (line.startsWith("+") && !line.startsWith("+++")) {
			current.additions = (current.additions ?? 0) + 1;
		} else if (line.startsWith("-") && !line.startsWith("---")) {
			current.deletions = (current.deletions ?? 0) + 1;
		}
	}

	flush();
	return results;
}
