const sqlite3 = require('sqlite3');

class Database {

	constructor(database, error, open, upgrade) {

		this.database = new sqlite3.Database(database, sqlite3.OPEN_READWRITE | sqlite3.OPEN_CREATE, e => {

			if (e === null) {

				open();

				this.database.serialize(() => {

					this.database.get(`PRAGMA user_version;`, (error, row) => {

						if (row['user_version'] < 1) {

							this.database.exec(`
								CREATE TABLE guilds (
									id TEXT PRIMARY KEY,
									command TEXT,
									enabled INT DEFAULT 1
								)
							`);

							this.database.exec(`
								CREATE TABLE guilds_servers (
									id TEXT NOT NULL,
									alias TEXT NOT NULL,
									address TEXT NOT NULL,
									password TEXT
								)
							`);

							this.database.exec(`PRAGMA user_version = 1`);

						}

						upgrade(row['user_version'], Database.VERSION);

					});

				});

			} else {
				error(e);
			}

		});

	}

	isGuildStatusCommand(id, command, callback) {

		this.database.get(`SELECT command, enabled FROM guilds WHERE id = ?`, id, (error, row) => {

			if (row && row['enabled'] !== 1) {
				return;
			}

			if (row && row['command'] && row['command'] === command.toLowerCase() || (!row || !row['command']) && command.match(/^(status|serverstatus|getstatus)$/i)) {
				callback(true);
			} else {
				callback(false);
			}

		});

	}

	getGuildStatusCommand(id, callback) {

		this.database.get(`SELECT command, enabled FROM guilds WHERE id = ?`, id, (error, row) => {

			if (row && row['enabled'] !== 1) {
				return;
			}

			if (row && row['command'] !== null) {
				callback(row['command']);
			} else {
				callback('status');
			}

		});

	}

	getSharedIP(id, callback) {

		if (id.length === 0) {
			callback([]);
			return;
		}

		// SQLite3 binding doesn't expand arrays into escaped sequences.
		this.database.all(`SELECT address FROM guilds_servers WHERE id IN ('${id.join("', '")}') AND alias = ? GROUP BY address ORDER BY id, rowid`, 'default', (error, rows) => {
			callback(rows.map(row => row['address']));
		});

	}

	ipGet(id, alias, callback) {
		this.database.all(`SELECT address, password FROM guilds_servers WHERE id = ? AND alias = ? ORDER BY rowid`, id, alias.toLowerCase(), (error, rows) => {
			callback(rows);
		});
	}

	ipSet(id, alias, ip) {

		this.database.serialize(() => {

			this.ipReset(id, alias);

			const statement = this.database.prepare(`INSERT INTO guilds_servers VALUES(?, ?, ?, ?)`);
			ip.map(s => statement.run(id, alias.toLowerCase(), s.address, s.password));
			statement.finalize();

		});

	}

	ipReset(id, alias) {
		this.database.run(`DELETE FROM guilds_servers WHERE id = ? AND alias = ?`, id, alias.toLowerCase());
	}

	ipGetAliases(id, callback) {
		this.database.all(`SELECT alias FROM guilds_servers WHERE id = ? GROUP BY alias ORDER BY alias`, id, (error, rows) => {
			callback(rows.map(row => row['alias']));
		});
	}

	checkGuildCreated(id, callback) {
		this.database.get(`SELECT * FROM guilds WHERE id = ?`, id, (error, row) => {

			if (row) {
				callback();
			} else {
				const statement = this.database.prepare(`INSERT INTO guilds VALUES(?, ?, ?)`);
				statement.run(id, null, 1);
				statement.finalize(() => callback());
			}

		});
	}

	directiveGet(id, directive, callback) {
		this.database.get(`SELECT * FROM guilds WHERE id = ?`, id, (error, row) => {
			callback(row ? row[directive] : null);
		});
	}

	directiveSet(id, directive, value) {
		this.checkGuildCreated(id, () => {
			if (directive === 'enabled' || directive === 'command') {
				this.database.run(`UPDATE guilds SET ${directive} = ? WHERE id = ?`, value, id);
			}
		});
	}

}

Database.VERSION = 1;

module.exports = Database;