var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { Metadata, PermissionProviderBase, } from '@memberjunction/core';
import { RegisterClass, UUIDsEqual } from '@memberjunction/global';
/**
 * Wraps `MJ: Query Permissions` behind the unified {@link PermissionProviderBase} contract.
 *
 * Query permissions are role-only and use existence semantics: a row indicates the role
 * is allowed to execute the query; the absence of a row denies it. There are no CRUD flags.
 * This provider exposes `Execute` as the single canonical action.
 *
 * `resourceType` is `"Queries"`. `resourceId` is the query ID.
 */
let QueryPermissionProvider = class QueryPermissionProvider extends PermissionProviderBase {
    constructor() {
        super(...arguments);
        this.DomainName = 'Query Permissions';
        this.Description = 'Role-based Execute permission on MJ queries. Row existence = permission granted.';
        this.SupportedGranteeTypes = ['Role'];
        this.SupportedActions = ['Execute'];
        this.SupportsDeny = false;
    }
    GetResourceTypes() {
        return ['Queries'];
    }
    async CheckPermission(user, _resourceType, resourceId, action) {
        if (action !== 'Execute') {
            return {
                Allowed: false,
                DomainName: this.DomainName,
                Reason: `Query Permissions only support Execute (got '${action}')`,
            };
        }
        if (!resourceId) {
            return {
                Allowed: false,
                DomainName: this.DomainName,
                Reason: 'Query permissions require a specific query ID',
            };
        }
        const rows = await this.fetchPermissionsForQuery(resourceId);
        const userRoleIds = (user.UserRoles ?? []).map((ur) => ur.RoleID);
        const match = rows.some((row) => userRoleIds.some((rid) => UUIDsEqual(row.RoleID, rid)));
        return {
            Allowed: match,
            DomainName: this.DomainName,
            Reason: match
                ? `User has a role that grants Execute on query '${resourceId}'`
                : `No role grants Execute on query '${resourceId}'`,
        };
    }
    async GetEffectivePermissions(user, _resourceType, resourceId) {
        const rows = await this.fetchPermissionsForQuery(resourceId);
        const userRoleIds = (user.UserRoles ?? []).map((ur) => ur.RoleID);
        const matchingRows = rows.filter((row) => userRoleIds.some((rid) => UUIDsEqual(row.RoleID, rid)));
        if (matchingRows.length === 0)
            return [];
        const nameMap = await this.bulkLookupNames('Queries', [resourceId]);
        const queryName = nameMap.get(resourceId);
        return matchingRows.map((row) => this.buildNormalizedPermission({
            resourceType: 'Queries', resourceId, resourceName: queryName,
            granteeType: 'User', granteeId: user.ID, granteeName: user.Name,
            actions: ['Execute'],
            sourceRecordId: row.ID,
        }));
    }
    async GetUserResources(user, resourceType) {
        if (resourceType && resourceType !== 'Queries')
            return [];
        const userRoleIds = (user.UserRoles ?? []).map((ur) => ur.RoleID);
        if (userRoleIds.length === 0)
            return [];
        const rows = await this.fetchRows('MJ: Query Permissions', `RoleID IN (${userRoleIds.map((r) => `'${r}'`).join(',')})`, ['ID', 'QueryID', 'RoleID', 'Query'], 'GetUserResources');
        // Deduplicate: multiple roles may grant the same query.
        const seen = new Set();
        const results = [];
        for (const row of rows) {
            if (seen.has(row.QueryID))
                continue;
            seen.add(row.QueryID);
            results.push(this.buildNormalizedPermission({
                resourceType: 'Queries', resourceId: row.QueryID,
                resourceName: row.Query ?? undefined,
                granteeType: 'User', granteeId: user.ID, granteeName: user.Name,
                actions: ['Execute'],
                sourceRecordId: row.ID,
            }));
        }
        return results;
    }
    async GetResourcePermissions(resourceType, resourceId, provider) {
        if (resourceType !== 'Queries')
            return [];
        const rows = await this.fetchPermissionsForQuery(resourceId);
        if (rows.length === 0)
            return [];
        const md = provider ?? new Metadata();
        const nameMap = await this.bulkLookupNames('Queries', [resourceId]);
        const queryName = nameMap.get(resourceId);
        return rows.map((row) => {
            const role = md.Roles.find((r) => UUIDsEqual(r.ID, row.RoleID));
            return this.buildNormalizedPermission({
                resourceType: 'Queries', resourceId, resourceName: queryName,
                granteeType: 'Role', granteeId: row.RoleID,
                granteeName: role?.Name ?? row.Role ?? undefined,
                actions: ['Execute'],
                sourceRecordId: row.ID,
            });
        });
    }
    async fetchPermissionsForQuery(queryId) {
        return this.fetchRows('MJ: Query Permissions', `QueryID='${queryId}'`, ['ID', 'QueryID', 'RoleID', 'Role'], 'fetchPermissionsForQuery');
    }
};
QueryPermissionProvider = __decorate([
    RegisterClass(PermissionProviderBase, 'MJQueryPermissionProvider')
], QueryPermissionProvider);
export { QueryPermissionProvider };
//# sourceMappingURL=QueryPermissionProvider.js.map