const { setSurvey, pool } = require('../connection');
const vessel = require('../vessel');
const { access, operations } = require('../../organisations');
const { ALERT, ERROR, WARNING, NOTICE, INFO, DEBUG } = require('DOUGAL_ROOT/debug')(__filename);

// Cache the per-project organisations access here
let projectsCache;


// Prime the cache directly from the database
async function read () {
	DEBUG("Reading projects from database");
	const text = `
		SELECT
			pid,
			meta->'organisations' AS organisations
		FROM public.projects;
	`;
	const res = await pool.query(text);
	return Object.fromEntries(res.rows.map( row => [ row.pid, row.organisations ] ));
}

/*
 * Called from the database events project configuration
 * change handler
 */
function setCache (projects) {
	DEBUG("Setting project organisations cache via setCache()");
	projectsCache = Object.fromEntries(Object.entries(projects).map( row => [ row[0], row[1].organisations ] ));
}

/*
 * Use this function to read `projectsCache`. Do NOT
 * read `projectsCache` directly as it might be undefined
 */
async function projectOrganisations (pid) {
	if (!projectsCache) {
		DEBUG("Priming projectsCache");
		projectsCache = await read();
	}

	return projectsCache[pid] ?? {}; // Every project should have an `organisations` property, but…
}

/*
 * Returns organisations associated with a vessel.
 * If no `vesselID` is provided, returns own vessel.
 */
async function vesselOrganisations (vesselID) {
	return (await vessel.info(vesselID))?.organisations ?? {};
}

/** Check whether a user has access to the project given by `pid`.
 *
 * If `pid` is `null`, check against vessel access.
 */
async function orgAccess (userOrgs, pid, operation) {
	const itemOrgs = pid === null
		? await vesselOrganisations()
		: await projectOrganisations(pid);

	return access(userOrgs, itemOrgs, operation);
}

/** Check to which operations the user has access to in the
 * project given by 'pid`.
 *
 * If `pid` is `null`, check against vessel access.
 */
async function allowedOperations (userOrgs, pid) {
	const itemOrgs = pid === null
		? await vesselOrganisations()
		: await projectOrganisations(pid);

	return operations(userOrgs, itemOrgs);
}

/*
 * Filter an array of objects by organisation access to a given operation
 */
function orgFilter (userOrgs, list, operation, fn = (item) => item.organisations ) {
	return list.filter ( (item) => access(userOrgs, fn(item), operation) );
}

module.exports = {
	setCache,
	projectOrganisations,
	vesselOrganisations,
	orgAccess,
	allowedOperations,
	orgFilter
};
