"""RBAC permissions and the default role -> permission matrix.

This is the executable form of the table in build plan Section 7.3. The
permission string values double as API-key scope names, so a key can be granted
the same capabilities as a role.
"""

from __future__ import annotations

from enum import Enum

from legate.policy.roles import Role


class Permission(str, Enum):
    # Manage workspace + billing
    MANAGE_WORKSPACE = "workspace:manage"
    # Manage members and roles
    MANAGE_MEMBERS = "members:manage"
    # Create/edit agents and workflows
    MANAGE_BUILD = "build:write"
    # Manage connectors and credentials
    MANAGE_CONNECTORS = "connectors:manage"
    # Run agents/workflows
    RUN = "runs:execute"
    # Approve sensitive actions
    APPROVE = "approvals:decide"
    # View runs and audit log
    VIEW = "read"


# Section 7.3 default matrix, transcribed exactly.
ROLE_PERMISSIONS: dict[Role, frozenset[Permission]] = {
    Role.OWNER: frozenset(Permission),  # every capability
    Role.ADMIN: frozenset(
        {
            Permission.MANAGE_MEMBERS,
            Permission.MANAGE_BUILD,
            Permission.MANAGE_CONNECTORS,
            Permission.RUN,
            Permission.APPROVE,
            Permission.VIEW,
        }
    ),
    Role.BUILDER: frozenset(
        {
            Permission.MANAGE_BUILD,
            Permission.MANAGE_CONNECTORS,
            Permission.RUN,
            Permission.VIEW,
        }
    ),
    Role.OPERATOR: frozenset(
        {
            Permission.RUN,
            Permission.APPROVE,
            Permission.VIEW,
        }
    ),
    Role.VIEWER: frozenset({Permission.VIEW}),
}


def role_has_permission(role: Role, permission: Permission) -> bool:
    """Return whether ``role`` grants ``permission`` per the default matrix."""
    return permission in ROLE_PERMISSIONS[role]


def scopes_for_role(role: Role) -> list[str]:
    """The API-key scope list equivalent to a role's permissions."""
    return sorted(p.value for p in ROLE_PERMISSIONS[role])


# A key carrying this scope is granted every permission.
WILDCARD_SCOPE = "*"


def scopes_have_permission(scopes: list[str], permission: Permission) -> bool:
    """Return whether an API-key scope list grants ``permission``."""
    return WILDCARD_SCOPE in scopes or permission.value in scopes
