/**
 * NEXUS permission enforcement - three-tier access control for cross-project operations.
 *
 * Permission model:
 *   read (1)    - Query tasks, discover relationships
 *   write (2)   - read + modify task fields, add relationships
 *   execute (3) - write + create/delete tasks, run commands
 *
 * Hierarchical: execute includes write includes read.
 * Same-project operations always have full permissions.
 *
 * @task T4574
 * @epic T4540
 */
import { ExitCode } from '@cleocode/contracts';
import { CleoError } from '../errors.js';
import { nexusGetProject, nexusSetPermission } from './registry.js';
// ── Constants ────────────────────────────────────────────────────────
const PERMISSION_LEVELS = {
    read: 1,
    write: 2,
    execute: 3,
};
// ── Functions ────────────────────────────────────────────────────────
/**
 * Convert a permission string to its numeric level.
 * Returns 0 for invalid/unknown permissions.
 */
export function permissionLevel(permission) {
    return PERMISSION_LEVELS[permission] ?? 0;
}
/**
 * Get the permission level for a registered project.
 * Returns 'read' as default if the project has no explicit permission.
 */
export async function getPermission(nameOrHash) {
    const project = await nexusGetProject(nameOrHash);
    if (!project)
        return 'read';
    return project.permissions ?? 'read';
}
/**
 * Check if a project has sufficient permissions (non-throwing).
 * Uses hierarchical comparison: execute >= write >= read.
 *
 * @returns true if the granted permission meets or exceeds the required level.
 */
export async function checkPermission(nameOrHash, required) {
    // Test bypass
    if (process.env['NEXUS_SKIP_PERMISSION_CHECK'] === 'true') {
        return true;
    }
    const granted = await getPermission(nameOrHash);
    return permissionLevel(granted) >= permissionLevel(required);
}
/**
 * Require a permission level or throw CleoError.
 * Used as a guard at the start of cross-project operations.
 */
export async function requirePermission(nameOrHash, required, operationName = 'operation') {
    // Test bypass
    if (process.env['NEXUS_SKIP_PERMISSION_CHECK'] === 'true') {
        return;
    }
    const granted = await getPermission(nameOrHash);
    if (permissionLevel(granted) < permissionLevel(required)) {
        throw new CleoError(ExitCode.NEXUS_PERMISSION_DENIED, `Permission denied: '${required}' required for '${operationName}' on project '${nameOrHash}' (granted: ${granted})`);
    }
}
/**
 * Full permission check returning a structured result.
 */
export async function checkPermissionDetail(nameOrHash, required) {
    const granted = await getPermission(nameOrHash);
    return {
        project: nameOrHash,
        required,
        granted,
        allowed: permissionLevel(granted) >= permissionLevel(required),
    };
}
/**
 * Set the permission level for a project.
 * Validates the permission value and updates the registry.
 * @task T4574
 */
export async function setPermission(nameOrHash, permission) {
    if (!nameOrHash) {
        throw new CleoError(ExitCode.INVALID_INPUT, 'Project name or hash required');
    }
    await nexusSetPermission(nameOrHash, permission);
}
/** Convenience: check read access. */
export async function canRead(nameOrHash) {
    return checkPermission(nameOrHash, 'read');
}
/** Convenience: check write access. */
export async function canWrite(nameOrHash) {
    return checkPermission(nameOrHash, 'write');
}
/** Convenience: check execute access. */
export async function canExecute(nameOrHash) {
    return checkPermission(nameOrHash, 'execute');
}
//# sourceMappingURL=permissions.js.map