import type { GitTreeEntry, GitTreeType } from '@gitlens/git/models/tree.js';
import { maybeStopWatch } from '@gitlens/utils/stopwatch.js';
import { iterateByDelimiter } from '@gitlens/utils/string.js';

export function parseGitTree(data: string | undefined, ref: string, singleEntry: boolean): GitTreeEntry[] {
	using sw = maybeStopWatch(`Git.parseTree`, { log: { onlyExit: true, level: 'debug' } });

	const trees: GitTreeEntry[] = [];
	if (!data) {
		sw?.stop({ suffix: ` no data` });
		return trees;
	}

	// Format: <mode> <type> <oid> <size>\t<path>

	let metadata: string;
	let oid: string;
	let size: number;
	let type: GitTreeType;
	let path: string;

	let startIndex: number;
	let endIndex: number;

	// Avoid generator if we are only parsing a single entry
	for (let line of singleEntry ? data.split('\n') : iterateByDelimiter(data, '\n')) {
		line = line.trim();
		if (!line) continue;

		[metadata, path] = line.split('\t');

		// Skip mode
		startIndex = metadata.indexOf(' ');
		if (startIndex === -1) continue;

		// Parse type
		startIndex++;
		endIndex = metadata.indexOf(' ', startIndex);
		if (endIndex === -1) continue;

		type = metadata.substring(startIndex, endIndex) as GitTreeType;

		// Parse oid
		startIndex = endIndex + 1;
		endIndex = metadata.indexOf(' ', startIndex);
		if (endIndex === -1) continue;

		oid = metadata.substring(startIndex, endIndex);

		// Parse size
		startIndex = endIndex + 1;

		size = parseInt(metadata.substring(startIndex), 10);

		trees.push({ ref: ref, oid: oid, path: path || '', size: isNaN(size) ? 0 : size, type: type || 'blob' });
	}

	sw?.stop({ suffix: ` parsed ${trees.length} trees` });

	return trees;
}
