const bodyParser = require('body-parser');
const express = require('express');
const app = express();
const qs = require('querystring');
const DB = require('./db/db');

const Databases  = {};
const Activation = {};

app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());

app.post('/connect', async (rq, rs) => {
	let err = checkDBArguments(rq.body)
	if(err) return rs.end(err);
	let token = Math.random().toString().substring(2);

	let { dir, entry, key, pass, bitrate } = rq.body;

	let db = new DB({
		directory: dir,
		entry: entry,
		key: key,
		bitrate: parseInt(bitrate)
	});

	if(await db.checkDB()) {
		Databases[token]  = db;
		Activation[token] = Date.now();

		rs.end(JSON.stringify({
			status: "OK",
			token: token
		}));
	} else {
		rs.end(JSON.stringify({
			status : "ERR",
			code   : "DB_NOT_EXISTS",
			message: "The specified database does not exists."
		}));
	}
});

app.post('/create', async (rq, rs) => {
	let err = checkDBArguments(rq.body)
	if(err) return rs.end(JSON.stringify(err));

	let { dir, entry, key, pass, bitrate } = rq.body;

	let db = new DB({
		directory: dir,
		entry: entry,
		key: key,
		bitrate: parseInt(bitrate)
	});
	try {
		await db.initDirectory();
	} catch (exc) {
		rs.end(JSON.stringify({
			status : "ERR",
			code   : "DB_NOT_ACCESIBLE",
			message: "The system cannot initializate the database."
		}));
		return;
	}

	let token = Math.random().toString().substring(2);


	Activation[token] = Date.now();
	Databases[token] = db;

	rs.end(JSON.stringify({
		status: "OK",
		token: token
	}));
});

app.use(async (rq, rs, next) => {
	if(rq.method !== "POST") return next();

	let { token } = rq.body;

	if(!Databases[token]) return rs.end(JSON.stringify({
		status : "ERR",
		code   : "INVALID_TOKEN",
		message: "The specified token is invalid, or it expired."
	}));
	
	Activation[token] = Date.now();
	rq.db = Databases[token];
	next();
});

app.post('/save', async (rq, rs, next) => {
	await rq.db.save();
	rs.end(JSON.stringify({ status: "OK" }));
});

app.post('/get', async (rq, rs) => {
	let data = await rq.db.get(rq.body.path);

	rs.end(JSON.stringify({ status: "OK", data: data }));
});

app.post('/all', async (rq, rs) => {
	let data = await rq.db.all();

	rs.end(JSON.stringify({ status: "OK", data: data }));
});

app.post('/set', async (rq, rs) => {
	let done = await rq.db.set(rq.body.path, rq.body.data);

	if(done) rs.end(JSON.stringify({ status: "OK" }));
	else rs.end(JSON.stringify({ status: "ERR", code: "NOT_ENOUGH_SPACE", message: "There is not enough space to contain the data." }));
});

app.post('/remove', async (rq, rs) => {
	let res = await rq.db.remove(rq.body.path);

	rs.end(JSON.stringify({ status: "OK", res: res }));
});

app.post('/keys', async (rq, rs) => {
	let res = await rq.db.keys(rq.body.path);

	rs.end(JSON.stringify({ status: "OK", res: res }));
});

app.post('/change-pass', async (rq, rs) => {
	let { new_pass, new_bitrate } = rq.body;

	await rq.db.changeCypher(new_pass, new_bitrate);

	rs.end(JSON.stringify({ status: "OK" }));
});

app.post('/reindex', async (rq, rs) => {
	let { new_pass, new_bitrate } = rq.body;

	await rq.db.changeCypher(rq.db.key, rq.db.bitrate);

	rs.end(JSON.stringify({ status: "OK" }));
});

app.post('/disconnect', async (rq, rs) => {
	await rq.db.unload();

	delete Databases[rq.body.token];
	delete Activation[rq.body.token];

	rs.end(JSON.stringify({ status: "OK" }));
});

app.post('/destroy-all', async (rq, rs) => {
	await rq.db.destroy();

	delete Databases[rq.body.token];
	delete Activation[rq.body.token];

	rs.end(JSON.stringify({ status: "OK" }));
});

app.listen(7878, () => console.log("Server Running!"));

function checkDBArguments(args) {
	if(!args.dir)     return { status: "ERR", code: "BAD_ARGUMENTS", message: "Please enter the container directory." };
	if(!args.entry)   return { status: "ERR", code: "BAD_ARGUMENTS", message: "Please enter the entry file." };
	if(!args.key)     return { status: "ERR", code: "BAD_ARGUMENTS", message: "Please enter the database password." };
	if(!args.bitrate) return { status: "ERR", code: "BAD_ARGUMENTS", message: "Please enter the database bitrate." };
}

process.on('uncaughtException', (err) => console.log(err));