/* 
 * tabcompletion.cpp
 * Tab completion module
 * Copyright (c) 2026 Daniel Hammer
 */ 

#include <montauk/string.h>
#include <montauk/syscall.h>
#include "shell.h"

#define RD_MAX 128

/*
	Does the file path end with .elf? 
*/
bool is_executable(const char* path) {
	size_t len = montauk::slen(path);

	if (len < 4) {
		return false;
	}

	if (path[len - 1] == 'f' &&
		path[len - 2] == 'l' &&
		path[len - 3] == 'e' && 
		path[len - 4] == '.')
	{
		return true;
	}

	return false;
}

int find_first_slash_pos(const char* string) {
	int i = 0;

	while (string[i] != '\0') {
		if (string[i] == '/') {
			return i;
		}

		i++;
	}

	return -1;
}

/*
	i.e., "shell.elf" => "shell"
*/
const char* strip_elf_extension(char* path) {
	size_t len = montauk::slen(path);

	path[len - 4] = '\0';

	return (const char*)path;
}

const char* build_montauk_path(
		char* buffer,
		size_t max,

		int volume_number,
		const char* subpath
	) {

	char volume_number_str[4]; // 3 digits (max. 999) + null byte
	int_to_str(volume_number, volume_number_str, 4);

												// example path:
	size_t vn_length = slen(volume_number_str); // 		0
	size_t subpath_length = slen(subpath);		// 		users/admin
	size_t bytes_required = vn_length + subpath_length + 2; // + ":" and "/" (full path 0:/users/admin)

	if (max < bytes_required) {
		return nullptr;
	}

	int pos = 0;

	for (size_t i = 0; i < vn_length; i++) {
		buffer[pos] = volume_number_str[i];
		pos++;
	}

	buffer[pos] = ':'; pos++;
	buffer[pos] = '/'; pos++;

	for (size_t i = 0; i < subpath_length; i++) {
		buffer[pos] = subpath[i];
		pos++;
	}

	return buffer;
}

const char* remove_path_prefix(
	const char* prefix, 	// users/admin
	const char* string 		// users/admin/config/
) {							// result: config/
	int pos = 0;

	while (string[pos] == prefix[pos]) {
		pos++;
	}

	return &string[pos];
}

int get_completions(		// returns no. of results 
		char*	string, 	// String to match/complete
		char**	array, 		// Array of strings containing completions
		int	arrayMax,

		char* cwd,
		int volume_number
	) {
	
	// --- System commands (0:/os/*.elf) ----
	const char* names[RD_MAX] 	= { };

	int n = montauk::readdir("0:/os", names, RD_MAX);
	int r = 0;

	for (int i = 0; i < n; i++) {
		/*
			Shift by n characters (names[i] + n),
			n = position of first slash in path + 1:
			
			"os/shell.elf" => "shell.elf"

			This is somewhat of a workaround. 
		*/
		int inc = find_first_slash_pos(names[i]) + 1;

		if (montauk::starts_with(names[i] + inc, (const char*)string)) {
			if (r >= arrayMax)
				break;

			if (!is_executable(names[i]))
				continue;

			char* p = (char *)names[i] + inc;
			strip_elf_extension(p);

			array[r] = (char *)p;
			r++;
		} 
	}

	// ---- Shell builtins ----

	size_t builtins_count = sizeof(shell_builtins) / sizeof(const char*);

	for (size_t i = 0; i < builtins_count; i++) {
		if (montauk::starts_with(shell_builtins[i], (const char*)string)) {
			if (r >= arrayMax)
				break;
			
			array[r] = (char *)shell_builtins[i];
			r++;
		}
	}

	// ---- cwd file matching ----

	if (cwd != nullptr) {
		char full_path[RD_MAX]		= { };
		build_montauk_path(full_path, RD_MAX, volume_number, cwd);

		const char* cwd_entries[RD_MAX] 	= { };

		int n = montauk::readdir(full_path, cwd_entries, RD_MAX);

		for (int i = 0; i < n; i++) {
			const char* cwd_entry_path = remove_path_prefix(cwd, cwd_entries[i]);

			if (cwd_entry_path[0] == '/') {
				cwd_entry_path++;
			}

			if (montauk::starts_with(cwd_entry_path, (const char*)string)) {
				if (r >= arrayMax)
					break;

				array[r] = (char *)cwd_entry_path;
				r++;
			}
		}
	}

	return r;
}
