import std::io;
import std::io::file;
import std::io::path;
import std::os::env;
import std::core::mem::allocator;
import std::collections::object;
import std::collections::list;
import std::encoding::json;


struct ConfigFile {
	Path path;
	String name;
}

alias StrList = list::List{String};
alias ConfFList = list::List{ConfigFile};


fn Path? String.to_expanded_path(&str, Allocator allocator)
{
	@pool() {
		StrList l;
		l.tinit();
		Path str_path = str.to_tpath()!;
	
		l.push(str_path.basename());
		Path? p = str_path.parent();
		while (true) {
			Path? x;
			if (try p) {
				String n = p.basename();
		
				// env variable
				if (n.starts_with("$")) {
					l.push(env::tget_var(n[1..]))!;
				} else {
					l.push(n);
				}
				
				x = p.parent();
			} else {
				break;
			}
			p = x;
		}

		Path path = path::temp("")!;
		foreach_r (idx, s: l) {
			path = path.tappend(s)!;
		}

		return path::new(allocator, path.str_view(), path.env);
	};
}

fn StrList? get_qemu_cmdline(Allocator allocator, Object* conf)
{
	StrList cmd;
	@pool() {
		// parse the disk path
		String disk = conf.get_string("disk")!;
		Path disk_path = disk.to_expanded_path(tmem)!;

		// compose the command line for the vm
		cmd.init(allocator);

		// first the executable
		cmd.push(conf.get_string("qemu"))!!;
		// then the drive
		cmd.push("-drive");
		cmd.push(string::format(allocator, "file=%s", disk_path.str_view()));
		// memory
		cmd.push("-m");
		cmd.push(conf.get_string("memory"))!!;
		// processors
		cmd.push("-smp");
		cmd.push(conf.get_string("processors") ?? "1");
		// then all the parameters
		Object* parameters = conf.get("parameters")!!;
		for (usz i = 0; i < parameters.get_len(); i++) {
			Object* p = parameters.get_at(i);
			if (p.is_string()) {
				cmd.push(string::format(allocator, "-%s", p.s));
			} else if (p.is_indexable()) {
				cmd.push(string::format(allocator, "-%s", p.get_string_at(0)))!!;
				cmd.push(p.get_string_at(1))!!;
			}
		}
	};

	return cmd;
}

fn ConfFList? get_config_list(Allocator allocator)
{
	ConfFList l;
	l.init(allocator);
	@pool() {
		// find the right config directory
		Path conf_dir = env::get_config_dir(tmem).append(tmem, "simple-qemu-manager")!;

		if (!file::exists(conf_dir.str_view()) || !file::is_dir(conf_dir.str_view())) {
			path::mkdir(conf_dir, recursive:true)!;
			return l;
		}

		// list all json files
		PathList pl = path::ls(tmem, conf_dir)!;
		foreach (fname : pl) @pool() {
			if ((fname.extension() ?? "") != "json") continue;
			Path fpath = conf_dir.append(tmem, fname.str_view())!;

			File cf = file::open_path(fpath, "r")!;
			defer (void)cf.close();

			Object* c = json::parse(tmem, &cf)!;
			ConfigFile e = {
				.path = path::new(allocator, fpath.str_view(), fpath.env)!,
				.name = string::format(allocator, "%s", c.get_string("name"))!,
			};
			l.push(e);
		};

	};

	return l;
}
