import { OrgRoles, SpiceDbProjectPermissions, SpiceDbResourceTypes } from "./types.js";
import { fromSpiceDbProjectId, toSpiceDbProjectId } from "./config.js";
import { checkPermission, lookupResources } from "./client.js";

//#region src/auth/authz/permissions.ts
/**
* SpiceDB Permission Check Functions
*
* High-level functions for checking project-level permissions.
*/
/**
* Check if a user can view a project.
*
* - If authz is disabled: returns true (current behavior)
* - If user is org owner/admin: returns true (bypass)
* - Otherwise: checks SpiceDB
*/
async function canViewProject(params) {
	if (params.orgRole === OrgRoles.OWNER || params.orgRole === OrgRoles.ADMIN) return true;
	return checkPermission({
		resourceType: SpiceDbResourceTypes.PROJECT,
		resourceId: toSpiceDbProjectId(params.tenantId, params.projectId),
		permission: SpiceDbProjectPermissions.VIEW,
		subjectType: SpiceDbResourceTypes.USER,
		subjectId: params.userId
	});
}
/**
* Check if a user can use a project (invoke agents, create API keys, view traces).
*
* - If authz is disabled: returns true (current behavior)
* - If user is org owner/admin: returns true (bypass)
* - Otherwise: checks SpiceDB for use permission
*/
async function canUseProject(params) {
	if (params.orgRole === OrgRoles.OWNER || params.orgRole === OrgRoles.ADMIN) return true;
	return checkPermission({
		resourceType: SpiceDbResourceTypes.PROJECT,
		resourceId: toSpiceDbProjectId(params.tenantId, params.projectId),
		permission: SpiceDbProjectPermissions.USE,
		subjectType: SpiceDbResourceTypes.USER,
		subjectId: params.userId
	});
}
/**
* Check if a user can use a project - always checks SpiceDB.
*
* Use this when orgRole is not available (e.g., run-api from JWT).
*/
async function canUseProjectStrict(params) {
	if (params.userId === "system" || params.userId.startsWith("apikey:")) return true;
	return checkPermission({
		resourceType: SpiceDbResourceTypes.PROJECT,
		resourceId: toSpiceDbProjectId(params.tenantId, params.projectId),
		permission: SpiceDbProjectPermissions.USE,
		subjectType: SpiceDbResourceTypes.USER,
		subjectId: params.userId
	});
}
/**
* Check if a user can edit a project (modify configurations).
*
* - If authz is disabled: only org owner/admin can edit
* - If user is org owner/admin: returns true (bypass)
* - Otherwise: checks SpiceDB for edit permission
*/
async function canEditProject(params) {
	if (params.orgRole === OrgRoles.OWNER || params.orgRole === OrgRoles.ADMIN) return true;
	return checkPermission({
		resourceType: SpiceDbResourceTypes.PROJECT,
		resourceId: toSpiceDbProjectId(params.tenantId, params.projectId),
		permission: SpiceDbProjectPermissions.EDIT,
		subjectType: SpiceDbResourceTypes.USER,
		subjectId: params.userId
	});
}
/**
* Get list of accessible project IDs for a user.
*
* - If authz is disabled: returns 'all' (no filtering needed)
* - If user is org owner/admin: returns 'all' (no filtering needed)
* - Otherwise: uses SpiceDB LookupResources
*/
async function listAccessibleProjectIds(params) {
	if (params.orgRole === OrgRoles.OWNER || params.orgRole === OrgRoles.ADMIN) return "all";
	return (await lookupResources({
		resourceType: SpiceDbResourceTypes.PROJECT,
		permission: SpiceDbProjectPermissions.VIEW,
		subjectType: SpiceDbResourceTypes.USER,
		subjectId: params.userId
	})).flatMap((id) => {
		try {
			const parsed = fromSpiceDbProjectId(id);
			return parsed.tenantId === params.tenantId ? [parsed.projectId] : [];
		} catch {
			return [];
		}
	});
}
/**
* Get list of usable project IDs for a user - always checks SpiceDB.
*/
async function listUsableProjectIds(params) {
	return (await lookupResources({
		resourceType: SpiceDbResourceTypes.PROJECT,
		permission: SpiceDbProjectPermissions.USE,
		subjectType: SpiceDbResourceTypes.USER,
		subjectId: params.userId
	})).flatMap((id) => {
		try {
			const parsed = fromSpiceDbProjectId(id);
			return parsed.tenantId === params.tenantId ? [parsed.projectId] : [];
		} catch {
			return [];
		}
	});
}

//#endregion
export { canEditProject, canUseProject, canUseProjectStrict, canViewProject, listAccessibleProjectIds, listUsableProjectIds };