import { logger } from "../logger/index.mjs";
import { HttpStatusCodes } from "./httpStatusCodes.mjs";

//#region src/utils/accessControl.ts
let AccessRule = /* @__PURE__ */ function(AccessRule$1) {
	AccessRule$1["none"] = "none";
	AccessRule$1["authenticated"] = "authenticated";
	AccessRule$1["admin"] = "admin";
	AccessRule$1["noneAuthenticated"] = "not-authenticated";
	AccessRule$1["hasOrganization"] = "has-organization";
	AccessRule$1["hasProject"] = "has-project";
	AccessRule$1["hasBearer"] = "has-bearer";
	AccessRule$1["oauth2"] = "oauth2";
	return AccessRule$1;
}({});
const accessControl = (res, accessRule) => {
	const accessRuleArray = Array.isArray(accessRule) ? accessRule : [accessRule];
	const { user, organization, project, authType } = res.locals;
	if (accessRuleArray.includes(AccessRule.none)) return {
		success: true,
		message: null,
		data: {
			user,
			organization,
			project,
			authType
		}
	};
	let success = true;
	const messages = [];
	if (accessRuleArray.includes(AccessRule.authenticated)) {
		if (!user) {
			success = false;
			messages.push("User is not authenticated");
		}
	}
	if (accessRuleArray.includes(AccessRule.noneAuthenticated)) {
		if (user) {
			success = false;
			messages.push("User is authenticated");
		}
	}
	if (accessRuleArray.includes(AccessRule.hasOrganization)) {
		if (!organization) {
			success = false;
			messages.push("Organization is not set");
		}
	}
	if (accessRuleArray.includes(AccessRule.hasProject)) {
		if (!project) {
			success = false;
			messages.push("Project is not set");
		}
	}
	if (accessRuleArray.includes(AccessRule.oauth2)) {
		if (authType !== "oauth2") {
			success = false;
			messages.push("OAuth2 authentication is required");
		}
	}
	const knownRules = Object.values(AccessRule);
	const unknownRules = accessRuleArray.filter((rule) => !knownRules.includes(rule));
	if (unknownRules.length > 0) {
		success = false;
		messages.push(`Unknown access rules: ${unknownRules.join(", ")}`);
	}
	return {
		success,
		message: messages.join(", "),
		data: {
			user,
			organization,
			project,
			authType
		}
	};
};
/**
* Middleware to control API access based on access rules.
*
* This middleware allows for multiple access rules to be passed, either as individual `AccessRule` or
* an array of `AccessRule` groups. Access is granted if at least one of the following conditions is met:
*
* - The user satisfies all `AccessRule` within any group of rules passed as an array.
* - The user satisfies any single `AccessRule` passed individually.
*
* Example usage:
*
* ```typescript
* // Allow access if the user has both `hasProject` and `hasOrganization`, or if they have `admin` rights
* app.use('/protected-route', apiAccessControlMiddleWare([AccessRule.hasProject, AccessRule.hasOrganization], AccessRule.admin));
* ```
*
* In this example:
* - The user will be granted access if they have both `hasProject` and `hasOrganization`.
* - Alternatively, the user will also be granted access if they have `admin` privileges.
*
* @param {...(AccessRule | AccessRule[])[]} accessRules - One or more access rules or groups of access rules.
* - Single `AccessRule`: The user must satisfy this rule for access to be granted.
* - Array of `AccessRule`: The user must satisfy all rules in the array for access to be granted.
* @returns {Function} Express middleware function that checks if the user has the required access.
*
* If the user does not meet any of the provided access rules, a 403 Forbidden status is returned.
*
* @example
* // Example 1: Require admin privileges
* app.use('/admin', apiAccessControlMiddleWare(AccessRule.admin));
*
* @example
* // Example 2: Require both project and organization access, or admin privileges
* app.use('/dashboard', apiAccessControlMiddleWare([AccessRule.hasProject, AccessRule.hasOrganization], AccessRule.admin));
*/
const accessControlMiddleWare = (...accessRules) => (_req, res, next) => {
	let hasAccess = false;
	for (const ruleGroup of accessRules) {
		if (Array.isArray(ruleGroup)) hasAccess = ruleGroup.map((rule) => accessControl(res, rule).success).every((result) => result);
		else if (accessControl(res, ruleGroup).success) hasAccess = true;
		if (hasAccess) break;
	}
	if (!hasAccess) {
		logger.error("Access denied");
		const errorStatusCode = HttpStatusCodes.FORBIDDEN_403;
		res.sendStatus(errorStatusCode);
		return;
	}
	next();
};

//#endregion
export { AccessRule, accessControl, accessControlMiddleWare };
//# sourceMappingURL=accessControl.mjs.map