/**
 * Healthcare supply-chain RBAC access-control module.
 * Provides role extraction, route-level permission checks, and Hono middleware.
 */
import { createMiddleware } from 'hono/factory';
export const ROLE_HIERARCHY = {
    VIEWER: 1,
    OPERATOR: 2,
    AUDITOR: 2,
    ADMIN: 3,
};
const ROUTE_PERMISSIONS = [
    { method: 'GET', pathPattern: /^\/api\/v1\/audit(\/|$)/, minRole: 'AUDITOR', description: 'audit trail access' },
    { method: 'POST', pathPattern: /^\/api\/v1\/inventory(\/|$)/, minRole: 'OPERATOR', description: 'inventory operations' },
    { method: 'POST', pathPattern: /^\/api\/v1\/transfers(\/|$)/, minRole: 'OPERATOR', description: 'transfer operations' },
    { method: 'POST', pathPattern: /^\/api\/v1\/procurement(\/|$)/, minRole: 'OPERATOR', description: 'procurement operations' },
    { method: 'POST', pathPattern: /^\/api\/v1\/risk\/scan$/, minRole: 'OPERATOR', description: 'risk scan' },
    { method: 'POST', pathPattern: /^\/api\/v1\/risk\/alerts\/[^/]+\/resolve$/, minRole: 'OPERATOR', description: 'resolve risk alert' },
    { method: 'POST', pathPattern: /^\/api\/v1\/risk\/recommendations\/[^/]+\/execute$/, minRole: 'OPERATOR', description: 'execute risk recommendation' },
    { method: 'POST', pathPattern: /^\/api\/v1\/forecasts(\/|$)/, minRole: 'OPERATOR', description: 'forecast operations' },
    { method: 'GET', pathPattern: /^\/api\/v1(\/|$)/, minRole: 'VIEWER', description: 'all reads' },
    { method: 'PUT', pathPattern: /^\/api\/v1(\/|$)/, minRole: 'ADMIN', description: 'config changes' },
    { method: 'DELETE', pathPattern: /^\/api\/v1(\/|$)/, minRole: 'ADMIN', description: 'deletions' },
];
const VALID_ROLES = new Set(['VIEWER', 'OPERATOR', 'ADMIN', 'AUDITOR']);
function isValidRole(value) {
    return typeof value === 'string' && VALID_ROLES.has(value);
}
function highestRole(roles) {
    let best;
    let bestLevel = 0;
    for (const r of roles) {
        if (isValidRole(r) && ROLE_HIERARCHY[r] > bestLevel) {
            best = r;
            bestLevel = ROLE_HIERARCHY[r];
        }
    }
    return best;
}
export function extractRole(iamClaims) {
    if (iamClaims === null || iamClaims === undefined || typeof iamClaims !== 'object') {
        return 'VIEWER';
    }
    const claims = iamClaims;
    if (isValidRole(claims['role'])) {
        return claims['role'];
    }
    if (Array.isArray(claims['roles'])) {
        const found = highestRole(claims['roles']);
        if (found)
            return found;
    }
    if (isValidRole(claims['custom:role'])) {
        return claims['custom:role'];
    }
    return 'VIEWER';
}
export function checkAccess(role, method, path) {
    const upperMethod = method.toUpperCase();
    if (role === 'ADMIN') {
        return { allowed: true };
    }
    if (role === 'AUDITOR') {
        if (upperMethod === 'GET') {
            return { allowed: true };
        }
        return { allowed: false, reason: `Role AUDITOR cannot ${upperMethod} ${path}` };
    }
    for (const perm of ROUTE_PERMISSIONS) {
        if (perm.method !== upperMethod || !perm.pathPattern.test(path)) {
            continue;
        }
        if (perm.minRole === 'AUDITOR') {
            return { allowed: false, reason: `Role ${role} cannot ${upperMethod} ${path}` };
        }
        if (ROLE_HIERARCHY[role] >= ROLE_HIERARCHY[perm.minRole]) {
            return { allowed: true };
        }
        return { allowed: false, reason: `Role ${role} cannot ${upperMethod} ${path}` };
    }
    return { allowed: true };
}
export function createAccessControlMiddleware(onDenied) {
    return createMiddleware(async (c, next) => {
        if (c.req.path.startsWith('/health')) {
            await next();
            return;
        }
        const iamClaims = c.get('iamClaims');
        const role = extractRole(iamClaims);
        const result = checkAccess(role, c.req.method, c.req.path);
        if (!result.allowed) {
            const correlationId = c.get('correlationId') ?? crypto.randomUUID();
            const actor = iamClaims?.['sub'] ?? 'unknown';
            if (onDenied) {
                await onDenied(correlationId, actor, role, c.req.method, c.req.path);
            }
            return c.json({
                error: { code: 'FORBIDDEN', message: result.reason },
                correlationId,
            }, 403);
        }
        c.set('userRole', role);
        await next();
    });
}
//# sourceMappingURL=access-control.js.map