
const fs = require('node:fs');
const path = require('node:path');

function mkdirSyncRecursive(filepath) {
	if (!fs.existsSync(filepath)) {
		mkdirSyncRecursive(filepath.substring(0, filepath.lastIndexOf(path.sep)));
		fs.mkdirSync(filepath);
	}
}

function isDirectory(filepath) {
	if (!fs.existsSync(filepath)) return false;
	return fs.lstatSync(filepath).isDirectory();
}

function readDir(filepath) {
	const dirContents = fs.readdirSync(filepath, { withFileTypes: true });
	return dirContents.map(entry => filepath + path.sep + entry.name).join('\n');
}

function removePrefix(basePath, prefix) {
	return basePath.replace(prefix, '');
}

function normalizeAndWriteFile(filePath, data) {
	filePath = path.normalize(filePath);
	fs.writeFileSync(filePath, data);
}

function normalizeAndAppendFile(filePath, data) {
	filePath = path.normalize(filePath);
	fs.appendFileSync(filePath, data);
}

function fileReader(path) {
	const fd = fs.openSync(path);
	// TODO: When Node v20 is EOL, replace this with the { bigint: true }
	// parameter variant.
	const size = BigInt(fs.fstatSync(fd).size);

	return {
		read: (bigPosition, bigLength) => {
			// Rust uses u64 for position/length which is transferred to JS as a BigInt.
			// Convert:
			const length = Number(bigLength);
			const position = Number(bigPosition);

			const data = Buffer.alloc(length);
			const sizeRead = fs.readSync(fd, data, { length, position });

			// Make data.size match the number of bytes read:
			return data.subarray(0, sizeRead);
		},
		size: () => {
			return size;
		},
		close: () => {
			fs.closeSync(fd);
		},
	};
}

function isWindows() {
	return process.platform === 'win32';
}

module.exports = {
	mkdirSyncRecursive,
	isDirectory,
	readDir,
	removePrefix,
	normalizeAndWriteFile,
	normalizeAndAppendFile,
	fileReader,
	isWindows,
};
