import { nanoid } from '../../nanoid.js';
export const Kind = 'Core#Permission';
const orderedRoles = ['reader', 'commenter', 'writer', 'owner'];
export class Permission {
    kind = Kind;
    /**
     * The data store key of the permission.
     * This property is generated by the store and is not writable.
     */
    key = '';
    /**
     * The type of the permission.
     *
     * - `user` can access the file by a specific user
     * - `group` can access the file by a group of users
     * - - `organization` the object can be searched by anyone within the organization.
     */
    type = 'user';
    /**
     * It represents the ID of the entity (user, group, or organization)
     * that is being granted the permission on a file or folder.
     */
    granteeId = '';
    /**
     * The role granted by this permission.
     */
    role = 'reader';
    /**
     * The "pretty" name to render with the permission.
     *
     * - `user` type - user's full name
     * - `group` type - the name of the group
     * - `organization` type - the organization name.
     */
    displayName;
    /**
     * Optional expiration date of the permission. This is the timestamp when the permission expires.
     * When creating / updating the permission the expiration date must:
     *
     * - be used on a user or a group
     * - the time must be in the future
     */
    expirationTime;
    /**
     * The store id of the user that added this permission.
     */
    addingUser = '';
    /**
     * The store id of the entity that is being granted the permission.
     */
    itemId = '';
    /**
     * The depth of the permission in the hierarchy.
     * When `0` it means that the permissions do not use inheritance.
     * When `1` it means the permission is set on the item itself.
     * When `2` it means the permission is set on the parent item.
     * When `3` it means the permission is set on the grandparent item, and so on.
     * This is used to determine the depth of the permission in the hierarchy.
     */
    depth = 0;
    /**
     * The source rule of the permission.
     * This is used to determine how the permission was granted.
     */
    sourceRule = 'direct_user_grant';
    /**
     * Creates a Permission object for a user.
     *
     * @param role The user role to set.
     * @param itemId The store id of the entity that is being granted the permission.
     * @param user The user id that has the role.
     * @param addingUser The key of the user that created this permission
     */
    static fromUserRole(role, itemId, user, addingUser) {
        const init = {
            key: nanoid(),
            kind: Kind,
            itemId,
            granteeId: user,
            role,
            type: 'user',
            addingUser,
            depth: 0,
            sourceRule: 'direct_user_grant',
        };
        return new Permission(init);
    }
    /**
     * Creates a Permission object for a group.
     *
     * @param role The group role to set.
     * @param itemId The store id of the entity that is being granted the permission.
     * @param group The group id that has the role.
     * @param addingUser The key of the user that created this permission
     */
    static fromGroupRole(role, itemId, group, addingUser) {
        const init = {
            key: nanoid(),
            kind: Kind,
            itemId,
            granteeId: group,
            role,
            type: 'group',
            addingUser,
            depth: 0,
            sourceRule: 'direct_user_grant',
        };
        return new Permission(init);
    }
    /**
     * Creates a Permission object for a group.
     *
     * @param role The group role to set.
     * @param itemId The store id of the entity that is being granted the permission.
     * @param addingUser The key of the user that created this permission
     */
    static fromOrganizationRole(role, itemId, organizationId, addingUser) {
        const init = {
            key: nanoid(),
            kind: Kind,
            itemId,
            granteeId: organizationId,
            role,
            type: 'organization',
            addingUser,
            depth: 0,
            sourceRule: 'direct_user_grant',
        };
        return new Permission(init);
    }
    /**
     * Creates a permission object from other than key and kind values.
     */
    static fromValues(init) {
        return new Permission({
            ...init,
            key: nanoid(),
            kind: Kind,
        });
    }
    constructor(input) {
        let init;
        if (typeof input === 'string') {
            init = JSON.parse(input);
        }
        else if (typeof input === 'object') {
            init = input;
        }
        else {
            init = {
                kind: Kind,
                key: nanoid(),
                granteeId: '',
                itemId: '',
                role: 'reader',
                type: 'user',
                addingUser: '',
                depth: 0,
                sourceRule: 'direct_user_grant',
            };
        }
        this.new(init);
    }
    new(init) {
        if (!Permission.isPermission(init)) {
            throw new Error(`Not a permission.`);
        }
        const { key = nanoid(), granteeId, role, type, displayName, expirationTime, addingUser, itemId, depth, sourceRule, } = init;
        this.kind = Kind;
        this.key = key;
        this.granteeId = granteeId;
        this.itemId = itemId;
        this.role = role;
        this.type = type;
        this.addingUser = addingUser;
        this.depth = depth || 0;
        this.sourceRule = sourceRule || 'direct_user_grant';
        if (displayName) {
            this.displayName = displayName;
        }
        else {
            this.displayName = undefined;
        }
        if (typeof expirationTime === 'number') {
            this.expirationTime = expirationTime;
        }
        else {
            this.expirationTime = undefined;
        }
    }
    static isPermission(input) {
        const typed = input;
        if (!input || typed.kind !== Kind) {
            return false;
        }
        return true;
    }
    /**
     * Checks whether the current user role meets the minimum required role.
     *
     * @param minimumLevel The minimum requested role
     * @param currentRole The user role. When not set it always returns false.
     * @returns True if the `currentRole` is at least the `minimumRole`
     */
    static hasRole(minimumLevel, currentRole) {
        if (!currentRole) {
            return false;
        }
        const currentAccessIndex = orderedRoles.indexOf(currentRole);
        const requestedAccessIndex = orderedRoles.indexOf(minimumLevel);
        // the current must be at least at the index of requested.
        return currentAccessIndex >= requestedAccessIndex;
    }
    /**
     * Checks if role1 is higher than role2 in the permission hierarchy.
     *
     * @param role1 The first role to compare.
     * @param role2 The second role to compare.
     * @returns `true` if `role1` is higher than `role2`, `false` otherwise.
     */
    static isHigherRole(role1, role2) {
        const role1Index = orderedRoles.indexOf(role1);
        const role2Index = orderedRoles.indexOf(role2);
        return role1Index > role2Index;
    }
    /**
     * Link to the `Permission.hasRole(minimumLevel, currentRole)`.
     * @see {@link Permission.hasRole}
     */
    hasRole(minimumLevel, currentRole) {
        return Permission.hasRole(minimumLevel, currentRole);
    }
    toJSON() {
        const result = {
            kind: Kind,
            key: this.key,
            role: this.role,
            type: this.type,
            addingUser: this.addingUser,
            granteeId: this.granteeId,
            itemId: this.itemId,
            depth: this.depth,
            sourceRule: this.sourceRule,
        };
        if (this.displayName) {
            result.displayName = this.displayName;
        }
        if (this.expirationTime) {
            result.expirationTime = this.expirationTime;
        }
        return result;
    }
}
//# sourceMappingURL=Permission.js.map