"""
School permission utilities.

Hierarchy:
  is_superuser | is_staff  → all permissions (always)
  everyone else            → role permissions UNION direct permissions
"""
from .models import SchoolPermission, UserSchoolRole, UserSchoolDirectPermission


def is_school_admin(user):
    return user.is_authenticated and (user.is_staff or user.is_superuser)


def get_user_permission_codenames(user):
    if not user.is_authenticated:
        return set()
    if user.is_staff or user.is_superuser:
        return set(SchoolPermission.objects.values_list('codename', flat=True))

    role_ids = UserSchoolRole.objects.filter(user_id=user.id).values_list('role_id', flat=True)
    from_roles = set(
        SchoolPermission.objects
        .filter(roles__id__in=role_ids)
        .values_list('codename', flat=True)
        .distinct()
    )
    direct = set(
        UserSchoolDirectPermission.objects
        .filter(user_id=user.id)
        .values_list('permission__codename', flat=True)
    )
    return from_roles | direct


def has_school_permission(user, codename):
    if not user.is_authenticated:
        return False
    if user.is_staff or user.is_superuser:
        return True
    role_ids = UserSchoolRole.objects.filter(user_id=user.id).values_list('role_id', flat=True)
    via_role = SchoolPermission.objects.filter(codename=codename, roles__id__in=role_ids).exists()
    if via_role:
        return True
    return UserSchoolDirectPermission.objects.filter(user_id=user.id, permission__codename=codename).exists()


class SchoolPermissionMixin:
    required_permission = None

    def check_school_permission(self, request):
        if not self.required_permission:
            return True
        return has_school_permission(request.user, self.required_permission)

    def permission_denied_response(self):
        from rest_framework.response import Response
        from rest_framework import status
        return Response(
            {'error': f'You do not have permission: {self.required_permission}'},
            status=status.HTTP_403_FORBIDDEN,
        )
