"""
Translate a staff member's effective fine-grained permissions into the
coarse, module-level CASL rules the Vue frontend uses to gate nav/routes,
plus the raw codename list the UI uses for fine-grained button-level gating.

Returned by the login payload so the SPA can drive access dynamically instead
of from the hardcoded department->subject mapping.
"""
from .models import Module, Permission
from .permissions import is_unrestricted, get_effective_permission_codenames

# Fine-grained action verb -> CASL action.
_ACTION_TO_CASL = {
    'view': 'read',
    'add': 'create',
    'edit': 'update',
    'delete': 'delete',
    'approve': 'update',
}


def _module_index():
    """code -> casl_subject for active modules (cached per request is fine)."""
    return {m.code: (m.casl_subject or '') for m in Module.objects.all()}


def build_ability_rules(staff_profile):
    """Return CASL rules: list of {action, subject}.

    Super admins get manage/all. Otherwise we grant a CASL action on a module
    subject if the user holds *any* fine-grained permission with that action in
    that module — enough for route/nav gating, while precise control stays in
    the codename list (see ``effective_permissions``).
    """
    if is_unrestricted(staff_profile):
        return [{'action': 'manage', 'subject': 'all'}]

    codenames = get_effective_permission_codenames(staff_profile)
    if not codenames:
        return [{'action': 'read', 'subject': 'Profile'}]

    module_subject = _module_index()
    # subject -> set of casl actions
    subject_actions = {}
    for codename in codenames:
        # codename == "<module>.<feature>.<action>"
        parts = codename.split('.')
        if len(parts) < 3:
            continue
        module_code, action = parts[0], parts[-1]
        subject = module_subject.get(module_code)
        if not subject:
            continue
        casl_action = _ACTION_TO_CASL.get(action, 'read')
        subject_actions.setdefault(subject, set()).add('read')  # any perm implies visibility
        subject_actions[subject].add(casl_action)

    rules = [{'action': 'read', 'subject': 'Profile'}]
    for subject, actions in subject_actions.items():
        for action in sorted(actions):
            rules.append({'action': action, 'subject': subject})
    return rules


def effective_permissions(staff_profile):
    """Sorted list of fine-grained codenames the staff member holds.

    For unrestricted users (super admins / system administrators) we return the
    compact wildcard ``['*']`` rather than the entire catalog. Returning all ~200
    codenames previously overflowed the browser cookie that stores the session
    user, intermittently corrupting it. The frontend treats ``'*'`` as "holds
    every permission" (see the auth store's ``hasPermission``).
    """
    if is_unrestricted(staff_profile):
        return ['*']
    return sorted(get_effective_permission_codenames(staff_profile))
