"""RBAC matrix coverage.

Verifies every cell of the Section 7.3 table against the implementation, so any
drift in the role -> permission mapping fails a test.
"""

from __future__ import annotations

import itertools

import pytest
from legate.policy.rbac import (
    Permission,
    role_has_permission,
    scopes_for_role,
    scopes_have_permission,
)
from legate.policy.roles import Role

# Section 7.3, transcribed independently of the implementation.
EXPECTED: dict[Permission, set[Role]] = {
    Permission.MANAGE_WORKSPACE: {Role.OWNER},
    Permission.MANAGE_MEMBERS: {Role.OWNER, Role.ADMIN},
    Permission.MANAGE_BUILD: {Role.OWNER, Role.ADMIN, Role.BUILDER},
    Permission.MANAGE_CONNECTORS: {Role.OWNER, Role.ADMIN, Role.BUILDER},
    Permission.RUN: {Role.OWNER, Role.ADMIN, Role.BUILDER, Role.OPERATOR},
    Permission.APPROVE: {Role.OWNER, Role.ADMIN, Role.OPERATOR},
    Permission.VIEW: {Role.OWNER, Role.ADMIN, Role.BUILDER, Role.OPERATOR, Role.VIEWER},
}


@pytest.mark.parametrize("role,permission", itertools.product(list(Role), list(Permission)))
def test_matrix_cell(role: Role, permission: Permission):
    expected = role in EXPECTED[permission]
    assert role_has_permission(role, permission) is expected


def test_owner_has_every_permission():
    for permission in Permission:
        assert role_has_permission(Role.OWNER, permission)


def test_viewer_has_only_view():
    granted = {p for p in Permission if role_has_permission(Role.VIEWER, p)}
    assert granted == {Permission.VIEW}


def test_scopes_for_role_match_permissions():
    scopes = scopes_for_role(Role.BUILDER)
    assert set(scopes) == {
        Permission.MANAGE_BUILD.value,
        Permission.MANAGE_CONNECTORS.value,
        Permission.RUN.value,
        Permission.VIEW.value,
    }


def test_scopes_have_permission_and_wildcard():
    assert scopes_have_permission([Permission.VIEW.value], Permission.VIEW)
    assert not scopes_have_permission([Permission.VIEW.value], Permission.MANAGE_MEMBERS)
    assert scopes_have_permission(["*"], Permission.MANAGE_WORKSPACE)
