import * as tfrpc from '/tfrpc.js';

let g_db;

tfrpc.register(async function todo_get_all() {
	let names = await todo_get_names();
	let result = [];
	for (let name of names) {
		result.push({
			name: name,
			items: await todo_get(name),
		});
	}
	return result;
});

async function todo_get_names() {
	return JSON.parse((await g_db.get('files')) ?? '[]');
}

async function todo_add(list) {
	let exchanged = false;
	let tries = 10;
	while (!exchanged && tries-- > 0) {
		let original = await g_db.get('files');
		let names = JSON.parse(original ?? '[]');
		let set = new Set(names);
		set.add(list);
		names = JSON.stringify([...set].sort());
		exchanged =
			original === names || (await g_db.exchange('files', original, names));
	}
	return exchanged;
}
tfrpc.register(todo_add);

async function todo_remove(list) {
	let exchanged = false;
	let tries = 10;
	while (!exchanged && tries-- > 0) {
		let original = await g_db.get('files');
		let names = JSON.parse(original ?? '[]');
		let set = new Set(names);
		set.delete(list);
		names = JSON.stringify([...set].sort());
		exchanged =
			original === names || (await g_db.exchange('files', original, names));
	}
	await g_db.remove('list:' + list);
	return exchanged;
}
tfrpc.register(todo_remove);

tfrpc.register(async function todo_rename(old_name, new_name) {
	if (await g_db.get('list:' + new_name)) {
		throw RuntimeError(`${new_name} already exists.`);
	}
	let list = await todo_get(old_name);
	await todo_set(new_name, list);
	await todo_add(new_name);
	await todo_remove(old_name);
});

async function todo_get(list) {
	try {
		let value = await g_db.get('list:' + list);
		return JSON.parse(value ?? '[]');
	} catch (error) {
		print(error);
		return [];
	}
}

async function todo_set(list, value) {
	await g_db.set('list:' + list, JSON.stringify(value));
}
tfrpc.register(todo_set);

async function main() {
	g_db = await database('todo');
	await app.setDocument(utf8Decode(getFile('index.html')));
}

main();
