"""
School role & permission views.

Permission hierarchy (checked on every relevant endpoint):
  is_superuser | is_staff  → treated as school admin, has ALL permissions
  everyone else            → permissions come from assigned SchoolRole(s)
"""
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.permissions import IsAuthenticated
from django.db import transaction
from django.contrib.auth import get_user_model

from .models import SchoolRole, SchoolPermission, SchoolRolePermission, UserSchoolRole, UserSchoolDirectPermission
from .serializers import SchoolRoleSerializer, SchoolPermissionSerializer
from .permissions import (
    is_school_admin,
    get_user_permission_codenames,
    has_school_permission,
)

User = get_user_model()
_CATEGORY_MAP = dict(SchoolPermission.CATEGORY_CHOICES)


def _user_row(user, role_map):
    """Build a user dict for list endpoints, marking staff automatically."""
    user_roles = role_map.get(user.id, [])
    full_access = user.is_staff or user.is_superuser
    return {
        'id': user.id,
        'username': user.username,
        'email': user.email,
        'first_name': user.first_name,
        'last_name': user.last_name,
        'is_active': user.is_active,
        'is_superuser': user.is_superuser,
        'is_staff': user.is_staff,
        'date_joined': user.date_joined,
        'last_login': user.last_login,
        'full_access': full_access,           # frontend badge
        'groups': user_roles,
        'groups_count': len(user_roles),
        'total_permissions': (
            SchoolPermission.objects.count() if full_access
            else sum(r.get('permissions_count', 0) for r in user_roles)
        ),
    }


# ─── CURRENT USER PERMISSIONS ────────────────────────────────────────────────

class MyPermissionsView(APIView):
    """
    GET /me/permissions/
    Returns the permission codenames the authenticated user holds in this school.
    Staff / superusers receive all permissions automatically.
    """
    permission_classes = [IsAuthenticated]

    def get(self, request):
        codenames = get_user_permission_codenames(request.user)
        all_perms = SchoolPermission.objects.filter(codename__in=codenames)
        by_category = {}
        for p in all_perms:
            label = _CATEGORY_MAP.get(p.category, p.category.title())
            by_category.setdefault(label, []).append(p.codename)

        return Response({
            'is_staff': request.user.is_staff,
            'is_superuser': request.user.is_superuser,
            'full_access': is_school_admin(request.user),
            'codenames': list(codenames),
            'by_category': by_category,
            'categories': sorted({p.category for p in all_perms}),
            'total': len(codenames),
        })


# ─── ROLES CRUD ───────────────────────────────────────────────────────────────

class SchoolRoleListCreateView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        roles = SchoolRole.objects.all()
        return Response(SchoolRoleSerializer(roles, many=True).data)

    def post(self, request):
        if not is_school_admin(request.user):
            return Response({'error': 'Only staff/admin can create roles.'}, status=status.HTTP_403_FORBIDDEN)
        name = request.data.get('name', '').strip()
        description = request.data.get('description', '').strip()
        if not name:
            return Response({'error': 'Name is required'}, status=status.HTTP_400_BAD_REQUEST)
        if SchoolRole.objects.filter(name=name).exists():
            return Response({'error': 'A role with this name already exists'}, status=status.HTTP_400_BAD_REQUEST)
        role = SchoolRole.objects.create(name=name, description=description)
        return Response(SchoolRoleSerializer(role).data, status=status.HTTP_201_CREATED)


class SchoolRoleDetailView(APIView):
    permission_classes = [IsAuthenticated]

    def _get(self, pk):
        try:
            return SchoolRole.objects.get(pk=pk)
        except SchoolRole.DoesNotExist:
            return None

    def get(self, request, pk):
        role = self._get(pk)
        if not role:
            return Response({'error': 'Role not found'}, status=status.HTTP_404_NOT_FOUND)
        return Response(SchoolRoleSerializer(role).data)

    def put(self, request, pk):
        if not is_school_admin(request.user):
            return Response({'error': 'Only staff/admin can edit roles.'}, status=status.HTTP_403_FORBIDDEN)
        role = self._get(pk)
        if not role:
            return Response({'error': 'Role not found'}, status=status.HTTP_404_NOT_FOUND)
        name = request.data.get('name', role.name).strip()
        description = request.data.get('description', role.description).strip()
        if not name:
            return Response({'error': 'Name is required'}, status=status.HTTP_400_BAD_REQUEST)
        if SchoolRole.objects.filter(name=name).exclude(pk=pk).exists():
            return Response({'error': 'A role with this name already exists'}, status=status.HTTP_400_BAD_REQUEST)
        role.name = name
        role.description = description
        role.save()
        return Response(SchoolRoleSerializer(role).data)

    def delete(self, request, pk):
        if not is_school_admin(request.user):
            return Response({'error': 'Only staff/admin can delete roles.'}, status=status.HTTP_403_FORBIDDEN)
        role = self._get(pk)
        if not role:
            return Response({'error': 'Role not found'}, status=status.HTTP_404_NOT_FOUND)
        role.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)


# ─── PERMISSION CATALOG ───────────────────────────────────────────────────────

class SchoolPermissionListView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        permissions = SchoolPermission.objects.all()

        # Annotate with usage counts
        perm_data = []
        for perm in permissions:
            roles_count = perm.roles.count()
            direct_count = UserSchoolDirectPermission.objects.filter(permission=perm).values('user_id').distinct().count()
            role_user_ids = set(
                UserSchoolRole.objects.filter(role__in=perm.roles.all()).values_list('user_id', flat=True)
            )
            perm_data.append({
                'id': perm.id,
                'name': perm.name,
                'codename': perm.codename,
                'category': perm.category,
                'content_type': _CATEGORY_MAP.get(perm.category, perm.category.title()),
                'description': perm.description,
                'groups_count': roles_count,
                'users_count': len(role_user_ids) + direct_count,
            })

        permissions_by_type = {}
        for p in perm_data:
            permissions_by_type.setdefault(p['content_type'], []).append(p)

        # Ordered list of unique human-readable category labels
        content_types = [label for _, label in SchoolPermission.CATEGORY_CHOICES]

        return Response({
            'permissions': perm_data,
            'permissions_by_type': permissions_by_type,
            'content_types': content_types,
        })

    def post(self, request):
        """Create a custom school permission."""
        if not is_school_admin(request.user):
            return Response({'error': 'Only staff/admin can create permissions.'}, status=status.HTTP_403_FORBIDDEN)
        name = request.data.get('name', '').strip()
        codename = request.data.get('codename', '').strip()
        category = request.data.get('content_type', request.data.get('category', '')).strip()
        description = request.data.get('description', '').strip()

        if not name or not codename:
            return Response({'error': 'name and codename are required'}, status=status.HTTP_400_BAD_REQUEST)
        if SchoolPermission.objects.filter(codename=codename).exists():
            return Response({'error': 'A permission with this codename already exists'}, status=status.HTTP_400_BAD_REQUEST)

        # Accept human label or raw key for category
        reverse_map = {v: k for k, v in _CATEGORY_MAP.items()}
        cat_key = reverse_map.get(category, category)

        perm = SchoolPermission.objects.create(
            name=name, codename=codename,
            category=cat_key, description=description,
        )
        return Response({
            'id': perm.id, 'name': perm.name, 'codename': perm.codename,
            'content_type': _CATEGORY_MAP.get(perm.category, perm.category),
            'category': perm.category, 'description': perm.description,
        }, status=status.HTTP_201_CREATED)


class SchoolPermissionDetailView(APIView):
    permission_classes = [IsAuthenticated]

    def _get(self, pk):
        try:
            return SchoolPermission.objects.get(pk=pk)
        except SchoolPermission.DoesNotExist:
            return None

    def put(self, request, pk):
        if not is_school_admin(request.user):
            return Response({'error': 'Only staff/admin can edit permissions.'}, status=status.HTTP_403_FORBIDDEN)
        perm = self._get(pk)
        if not perm:
            return Response({'error': 'Permission not found'}, status=status.HTTP_404_NOT_FOUND)
        perm.name = request.data.get('name', perm.name).strip() or perm.name
        perm.description = request.data.get('description', perm.description).strip()
        raw_cat = request.data.get('content_type', request.data.get('category', '')).strip()
        if raw_cat:
            reverse_map = {v: k for k, v in _CATEGORY_MAP.items()}
            perm.category = reverse_map.get(raw_cat, raw_cat)
        perm.save()
        return Response({
            'id': perm.id, 'name': perm.name, 'codename': perm.codename,
            'content_type': _CATEGORY_MAP.get(perm.category, perm.category),
            'category': perm.category, 'description': perm.description,
        })

    def delete(self, request, pk):
        if not is_school_admin(request.user):
            return Response({'error': 'Only staff/admin can delete permissions.'}, status=status.HTTP_403_FORBIDDEN)
        perm = self._get(pk)
        if not perm:
            return Response({'error': 'Permission not found'}, status=status.HTTP_404_NOT_FOUND)
        perm.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)


# ─── ROLE ↔ PERMISSION ───────────────────────────────────────────────────────

class RolePermissionsView(APIView):
    permission_classes = [IsAuthenticated]

    def _role(self, pk):
        try:
            return SchoolRole.objects.get(pk=pk)
        except SchoolRole.DoesNotExist:
            return None

    def get(self, request, pk):
        role = self._role(pk)
        if not role:
            return Response({'error': 'Role not found'}, status=status.HTTP_404_NOT_FOUND)

        all_perms = SchoolPermission.objects.all()
        current_ids = list(role.permissions.values_list('id', flat=True))
        current = all_perms.filter(id__in=current_ids)
        available = all_perms.exclude(id__in=current_ids)

        permissions_by_type = {}
        for perm in all_perms:
            label = _CATEGORY_MAP.get(perm.category, perm.category.title())
            permissions_by_type.setdefault(label, []).append({
                'id': perm.id,
                'name': perm.name,
                'codename': perm.codename,
                'content_type': perm.category,
            })

        return Response({
            'current_permissions': SchoolPermissionSerializer(current, many=True).data,
            'available_permissions': SchoolPermissionSerializer(available, many=True).data,
            'permissions_by_type': permissions_by_type,
            'current_ids': current_ids,
        })


class AssignRolePermissionsView(APIView):
    permission_classes = [IsAuthenticated]

    def post(self, request, pk):
        if not is_school_admin(request.user):
            return Response({'error': 'Only staff/admin can assign permissions.'}, status=status.HTTP_403_FORBIDDEN)
        try:
            role = SchoolRole.objects.get(pk=pk)
        except SchoolRole.DoesNotExist:
            return Response({'error': 'Role not found'}, status=status.HTTP_404_NOT_FOUND)
        ids = request.data.get('permission_ids', [])
        if not isinstance(ids, list):
            return Response({'error': 'permission_ids must be a list'}, status=status.HTTP_400_BAD_REQUEST)
        perms = SchoolPermission.objects.filter(id__in=ids)
        with transaction.atomic():
            for perm in perms:
                SchoolRolePermission.objects.get_or_create(role=role, permission=perm)
        return Response({
            'message': f'{perms.count()} permissions assigned to "{role.name}"',
            'permissions_count': role.role_permissions.count(),
        })


class RemoveRolePermissionsView(APIView):
    permission_classes = [IsAuthenticated]

    def post(self, request, pk):
        if not is_school_admin(request.user):
            return Response({'error': 'Only staff/admin can remove permissions.'}, status=status.HTTP_403_FORBIDDEN)
        try:
            role = SchoolRole.objects.get(pk=pk)
        except SchoolRole.DoesNotExist:
            return Response({'error': 'Role not found'}, status=status.HTTP_404_NOT_FOUND)
        ids = request.data.get('permission_ids', [])
        if not isinstance(ids, list):
            return Response({'error': 'permission_ids must be a list'}, status=status.HTTP_400_BAD_REQUEST)
        removed, _ = SchoolRolePermission.objects.filter(role=role, permission_id__in=ids).delete()
        return Response({
            'message': f'{removed} permissions removed from "{role.name}"',
            'permissions_count': role.role_permissions.count(),
        })


class UpdateRolePermissionsView(APIView):
    permission_classes = [IsAuthenticated]

    def put(self, request, pk):
        if not is_school_admin(request.user):
            return Response({'error': 'Only staff/admin can update permissions.'}, status=status.HTTP_403_FORBIDDEN)
        try:
            role = SchoolRole.objects.get(pk=pk)
        except SchoolRole.DoesNotExist:
            return Response({'error': 'Role not found'}, status=status.HTTP_404_NOT_FOUND)
        ids = request.data.get('permission_ids', [])
        if not isinstance(ids, list):
            return Response({'error': 'permission_ids must be a list'}, status=status.HTTP_400_BAD_REQUEST)
        perms = SchoolPermission.objects.filter(id__in=ids)
        with transaction.atomic():
            SchoolRolePermission.objects.filter(role=role).delete()
            SchoolRolePermission.objects.bulk_create([
                SchoolRolePermission(role=role, permission=p) for p in perms
            ])
        return Response({
            'message': f'Permissions updated for "{role.name}"',
            'permissions_count': role.role_permissions.count(),
        })


# ─── USER ↔ ROLE ──────────────────────────────────────────────────────────────

class UserRoleListView(APIView):
    """
    All school users with their assigned roles.
    Staff/superusers are flagged as full_access=True — their permissions
    come from is_staff/is_superuser, not from role assignments.
    """
    permission_classes = [IsAuthenticated]

    def get(self, request):
        from master_admin.models import UserProfile
        school = getattr(request, 'school', None)
        if school:
            profiles = (
                UserProfile.objects
                .filter(school=school)
                .select_related('user')
                .using('default')
            )
        else:
            profiles = UserProfile.objects.none()

        role_map = {}
        for usr in UserSchoolRole.objects.select_related('role').all():
            role_map.setdefault(usr.user_id, []).append({
                'id': usr.role.id,
                'name': usr.role.name,
                'permissions_count': usr.role.role_permissions.count(),
            })

        return Response({'users': [_user_row(p.user, role_map) for p in profiles]})


class UserRolesDetailView(APIView):
    """
    GET  /users/<id>/roles/
    Returns current + available roles.
    If the user is staff/superuser, current_groups is empty (they have
    full access inherently) but you can still assign roles for reference.
    """
    permission_classes = [IsAuthenticated]

    def get(self, request, user_id):
        try:
            target_user = User.objects.using('default').get(pk=user_id)
        except User.DoesNotExist:
            return Response({'error': 'User not found'}, status=status.HTTP_404_NOT_FOUND)

        current_objs = UserSchoolRole.objects.filter(user_id=user_id).select_related('role')
        current_ids = [o.role_id for o in current_objs]
        current_roles = [
            {
                'id': o.role.id,
                'name': o.role.name,
                'users_count': o.role.user_assignments.count(),
                'permissions_count': o.role.role_permissions.count(),
            }
            for o in current_objs
        ]
        available_roles = [
            {
                'id': r.id,
                'name': r.name,
                'users_count': r.user_assignments.count(),
                'permissions_count': r.role_permissions.count(),
            }
            for r in SchoolRole.objects.exclude(id__in=current_ids)
        ]
        return Response({
            'current_groups': current_roles,
            'available_groups': available_roles,
            'full_access': target_user.is_staff or target_user.is_superuser,
            'is_staff': target_user.is_staff,
            'is_superuser': target_user.is_superuser,
        })


class AssignUserRoleView(APIView):
    permission_classes = [IsAuthenticated]

    def post(self, request, user_id):
        if not is_school_admin(request.user):
            return Response({'error': 'Only staff/admin can assign roles.'}, status=status.HTTP_403_FORBIDDEN)
        role_ids = request.data.get('group_ids', request.data.get('role_ids', []))
        if not isinstance(role_ids, list):
            return Response({'error': 'role_ids must be a list'}, status=status.HTTP_400_BAD_REQUEST)
        assigned = 0
        for rid in role_ids:
            try:
                role = SchoolRole.objects.get(pk=rid)
                _, created = UserSchoolRole.objects.get_or_create(
                    user_id=user_id, role=role,
                    defaults={'assigned_by_id': request.user.id},
                )
                if created:
                    assigned += 1
            except SchoolRole.DoesNotExist:
                pass
        return Response({'message': f'{assigned} roles assigned to user {user_id}'})


class RemoveUserRoleView(APIView):
    permission_classes = [IsAuthenticated]

    def post(self, request, user_id):
        if not is_school_admin(request.user):
            return Response({'error': 'Only staff/admin can remove roles.'}, status=status.HTTP_403_FORBIDDEN)
        role_ids = request.data.get('group_ids', request.data.get('role_ids', []))
        if not isinstance(role_ids, list):
            return Response({'error': 'role_ids must be a list'}, status=status.HTTP_400_BAD_REQUEST)
        removed, _ = UserSchoolRole.objects.filter(user_id=user_id, role_id__in=role_ids).delete()
        return Response({'message': f'{removed} roles removed from user {user_id}'})


class UserDetailView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request, user_id):
        try:
            user = User.objects.using('default').get(pk=user_id)
        except User.DoesNotExist:
            return Response({'error': 'User not found'}, status=status.HTTP_404_NOT_FOUND)

        full_access = user.is_staff or user.is_superuser
        roles = [
            {'id': o.role.id, 'name': o.role.name}
            for o in UserSchoolRole.objects.filter(user_id=user_id).select_related('role')
        ]
        return Response({
            'id': user.id,
            'username': user.username,
            'email': user.email,
            'first_name': user.first_name,
            'last_name': user.last_name,
            'is_active': user.is_active,
            'is_superuser': user.is_superuser,
            'is_staff': user.is_staff,
            'full_access': full_access,
            'date_joined': user.date_joined,
            'last_login': user.last_login,
            'groups': roles,
        })


class BulkAssignRolesView(APIView):
    permission_classes = [IsAuthenticated]

    def post(self, request):
        if not is_school_admin(request.user):
            return Response({'error': 'Only staff/admin can bulk assign roles.'}, status=status.HTTP_403_FORBIDDEN)
        user_ids = request.data.get('user_ids', [])
        role_ids = request.data.get('group_ids', request.data.get('role_ids', []))
        roles = SchoolRole.objects.filter(id__in=role_ids)
        assigned = 0
        with transaction.atomic():
            for uid in user_ids:
                for role in roles:
                    _, created = UserSchoolRole.objects.get_or_create(
                        user_id=uid, role=role,
                        defaults={'assigned_by_id': request.user.id},
                    )
                    if created:
                        assigned += 1
        return Response({'message': f'{assigned} role assignments created'})


class BulkRemoveRolesView(APIView):
    permission_classes = [IsAuthenticated]

    def post(self, request):
        if not is_school_admin(request.user):
            return Response({'error': 'Only staff/admin can bulk remove roles.'}, status=status.HTTP_403_FORBIDDEN)
        user_ids = request.data.get('user_ids', [])
        role_ids = request.data.get('group_ids', request.data.get('role_ids', []))
        removed, _ = UserSchoolRole.objects.filter(user_id__in=user_ids, role_id__in=role_ids).delete()
        return Response({'message': f'{removed} role assignments removed'})


# ─── PERMISSION DETAIL (for RolePermissions.jsx) ─────────────────────────────

class PermissionDetailView(APIView):
    """GET /permissions/<id>/details/ — which roles use this permission."""
    permission_classes = [IsAuthenticated]

    def get(self, request, pk):
        try:
            perm = SchoolPermission.objects.get(pk=pk)
        except SchoolPermission.DoesNotExist:
            return Response({'error': 'Permission not found'}, status=status.HTTP_404_NOT_FOUND)

        roles = perm.roles.all()
        role_ids = list(roles.values_list('id', flat=True))
        users_affected = UserSchoolRole.objects.filter(role_id__in=role_ids).values('user_id').distinct().count()
        direct_users = UserSchoolDirectPermission.objects.filter(permission=perm).values('user_id').distinct().count()

        return Response({
            'id': perm.id,
            'name': perm.name,
            'codename': perm.codename,
            'category': perm.category,
            'content_type': perm.category,
            'description': perm.description,
            'groups_count': roles.count(),
            'users_count': users_affected + direct_users,
            'roles': [{'id': r.id, 'name': r.name} for r in roles],
        })


# ─── USER DIRECT PERMISSIONS (for UserPermission.jsx) ────────────────────────

class UserPermissionStatsView(APIView):
    """GET /users/permissions/stats/ — all school users with permission counts."""
    permission_classes = [IsAuthenticated]

    def get(self, request):
        from master_admin.models import UserProfile
        school = getattr(request, 'school', None)
        if school:
            profiles = (
                UserProfile.objects
                .filter(school=school)
                .select_related('user')
                .using('default')
            )
        else:
            profiles = UserProfile.objects.none()

        # Pre-fetch counts
        role_map = {}
        for usr in UserSchoolRole.objects.select_related('role').all():
            role_map.setdefault(usr.user_id, []).append(usr.role_id)

        direct_map = {}
        for dp in UserSchoolDirectPermission.objects.all():
            direct_map[dp.user_id] = direct_map.get(dp.user_id, 0) + 1

        all_perm_count = SchoolPermission.objects.count()
        users_data = []
        for profile in profiles:
            u = profile.user
            full_access = u.is_staff or u.is_superuser
            role_ids = role_map.get(u.id, [])
            group_perm_count = (
                SchoolPermission.objects
                .filter(roles__id__in=role_ids)
                .distinct().count()
            ) if role_ids else 0
            direct_count = direct_map.get(u.id, 0)
            users_data.append({
                'id': u.id,
                'username': u.username,
                'email': u.email,
                'is_active': u.is_active,
                'is_superuser': u.is_superuser,
                'is_staff': u.is_staff,
                'full_access': full_access,
                'direct_permissions_count': all_perm_count if full_access else direct_count,
                'group_permissions_count': all_perm_count if full_access else group_perm_count,
                'total_permissions_count': all_perm_count if full_access else len(
                    set(
                        list(SchoolPermission.objects.filter(roles__id__in=role_ids).values_list('id', flat=True)) +
                        list(UserSchoolDirectPermission.objects.filter(user_id=u.id).values_list('permission_id', flat=True))
                    )
                ),
            })

        return Response({'users': users_data})


class UserPermissionsView(APIView):
    """
    GET /users/<user_id>/permissions/
    Returns direct permissions, role-based permissions, and available permissions.
    """
    permission_classes = [IsAuthenticated]

    def get(self, request, user_id):
        try:
            user = User.objects.using('default').get(pk=user_id)
        except User.DoesNotExist:
            return Response({'error': 'User not found'}, status=status.HTTP_404_NOT_FOUND)

        all_perms = SchoolPermission.objects.all()
        full_access = user.is_staff or user.is_superuser

        # Direct permissions
        direct_ids = list(
            UserSchoolDirectPermission.objects.filter(user_id=user_id).values_list('permission_id', flat=True)
        )

        # Role-based permissions
        role_objs = UserSchoolRole.objects.filter(user_id=user_id).select_related('role')
        role_ids = [r.role_id for r in role_objs]
        group_perm_ids = list(
            SchoolPermission.objects.filter(roles__id__in=role_ids).values_list('id', flat=True).distinct()
        ) if role_ids else []

        if full_access:
            current = all_perms
            direct_perms = all_perms
            group_perms = all_perms
            available = SchoolPermission.objects.none()
        else:
            current_ids = list(set(direct_ids + group_perm_ids))
            current = all_perms.filter(id__in=current_ids)
            direct_perms = all_perms.filter(id__in=direct_ids)
            group_perms = all_perms.filter(id__in=group_perm_ids)
            available = all_perms.exclude(id__in=direct_ids)

        def _perm(p):
            return {
                'id': p.id, 'name': p.name, 'codename': p.codename,
                'content_type': p.category, 'category': p.category,
            }

        return Response({
            'full_access': full_access,
            'current_permissions': [_perm(p) for p in current],
            'direct_permissions': [_perm(p) for p in direct_perms],
            'group_permissions': [_perm(p) for p in group_perms],
            'available_permissions': [_perm(p) for p in available],
            'user_groups': [
                {'id': r.role.id, 'name': r.role.name,
                 'permissions_count': r.role.role_permissions.count()}
                for r in role_objs
            ],
        })


class AssignUserDirectPermissionView(APIView):
    """POST /users/<user_id>/permissions/assign/"""
    permission_classes = [IsAuthenticated]

    def post(self, request, user_id):
        if not is_school_admin(request.user):
            return Response({'error': 'Only staff/admin can assign permissions.'}, status=status.HTTP_403_FORBIDDEN)
        ids = request.data.get('permission_ids', [])
        if not isinstance(ids, list):
            return Response({'error': 'permission_ids must be a list'}, status=status.HTTP_400_BAD_REQUEST)
        perms = SchoolPermission.objects.filter(id__in=ids)
        assigned = 0
        with transaction.atomic():
            for perm in perms:
                _, created = UserSchoolDirectPermission.objects.get_or_create(
                    user_id=user_id, permission=perm,
                    defaults={'granted_by_id': request.user.id},
                )
                if created:
                    assigned += 1
        return Response({'message': f'{assigned} permissions assigned to user {user_id}'})


class RemoveUserDirectPermissionView(APIView):
    """POST /users/<user_id>/permissions/remove/"""
    permission_classes = [IsAuthenticated]

    def post(self, request, user_id):
        if not is_school_admin(request.user):
            return Response({'error': 'Only staff/admin can remove permissions.'}, status=status.HTTP_403_FORBIDDEN)
        ids = request.data.get('permission_ids', [])
        if not isinstance(ids, list):
            return Response({'error': 'permission_ids must be a list'}, status=status.HTTP_400_BAD_REQUEST)
        removed, _ = UserSchoolDirectPermission.objects.filter(
            user_id=user_id, permission_id__in=ids
        ).delete()
        return Response({'message': f'{removed} permissions removed from user {user_id}'})
