const os = require('os');
const { statfs } = require('fs').promises;
const { pool } = require('./db/connection');
const cfg = require('./config');
const { ALERT, ERROR, WARNING, NOTICE, INFO, DEBUG } = require('DOUGAL_ROOT/debug')(__filename);


/** Return filesystem statistics
 */
async function df (fs="/") {
	const s = await statfs(fs);

	if (s) {
		const total = (s.bsize * s.blocks); // bytes
		const free = (s.bfree * s.bsize);
		const available = (s.bavail * s.bsize);
		const used = total - free;
		const usedPercent = used/total * 100
		return {
			total,
			free,
			available,
			used,
			usedPercent
		}
	}
}

/** Return the size of the Dougal database
 */
async function dbSize () {
	const client = await pool.connect();
	let res;
	try {
		res = (await client.query("SELECT pg_database_size(current_database()) size;"))?.rows[0];
	} catch (err) {
		ERROR(err);
	} finally {
		client.release();
	}
	return res;
}

async function dbSchemaSizes () {
	const text = `
		SELECT pid,
			(sum(table_size)::bigint) size,
			((sum(table_size) / pg_database_size(current_database())) * 100) percent
		FROM (
		SELECT pg_catalog.pg_namespace.nspname as schema_name,
				pg_relation_size(pg_catalog.pg_class.oid) as table_size
		FROM   pg_catalog.pg_class
			JOIN pg_catalog.pg_namespace ON relnamespace = pg_catalog.pg_namespace.oid
		) t
		JOIN public.projects p ON schema_name = p.schema
		GROUP BY pid
		ORDER BY pid
	`;

	const client = await pool.connect();
	let res;
	try {
		res = (await client.query(text))?.rows;
	} catch (err) {
		ERROR(err);
	} finally {
		client.release();
	}
	return res;
}

async function diagnostics () {
	const paths = cfg._("global.imports.paths") ?? {};
	const data = {};
	for (path in paths) {
		data[path] = await df(paths[path]);
	}
	const res = {
		hostname: os.hostname(),
		memory: {
			total: os.totalmem(),
			free: os.freemem()
		},
		uptime: os.uptime(),
		loadavg: os.loadavg(),
		networkInterfaces: os.networkInterfaces(),
		cpus: os.cpus(),
		storage: {
			root: await df("/"),
			data
		},
		database: {
			...(await dbSize()),
			projects: Object.fromEntries((await dbSchemaSizes()).map(row => [ row.pid, {size: row.size, percent: row.percent} ]))
		}
	};

	return res;
}


module.exports = diagnostics;
