# core/permissions.py
"""
Role-based permission system for Rapha-Bethel BNPS
=====================================================
ROLE HIERARCHY (higher = more access)
  superuser   : 999  — developer, full access
  proprietor  : 100  — school owner, full access
  head_master : 90   — English section head, all school ops
  head_mistress:90   — French section head, all school ops
  bursar      : 80   — finance full access, read others
  admin       : 70   — office admin, most ops except finance delete
  class_teacher:60   — own class students + attendance + SMS to class parents
  teacher     : 60   — same as class_teacher
  subject_teacher:50 — own subjects, attendance, read own class students
  assistant_teacher:45 — mark attendance only, read students
  secretary   : 40   — read most, create announcements
  support     : 20   — (driver/cleaner/security/canteen) own leave/attendance only
  parent      : 0    — parent portal only (separate login)
"""

from django.core.exceptions import PermissionDenied
from django.shortcuts import redirect
from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin

ROLE_HIERARCHY = {
    'proprietor':       100,
    'head_master':       90,
    'head_mistress':     90,
    'bursar':            80,
    'admin':             70,
    'class_teacher':     60,
    'teacher':           60,
    'subject_teacher':   50,
    'assistant_teacher': 45,
    'secretary':         40,
    'driver':            20,
    'cleaner':           20,
    'canteen':           20,
    'security':          20,
    'support':           20,
    'other':             20,
}

# Permission levels for each action category
PERM = {
    # Students
    'student_view_all':    65,   # admin+
    'student_view_class':  45,   # teachers see own class
    'student_add':         70,   # admin+
    'student_edit':        70,
    'student_delete':      90,   # head+
    'student_import':      70,
    'parent_manage':       70,

    # Academics
    'class_view':          45,
    'class_manage':        70,   # admin+
    'subject_view':        45,
    'subject_manage':      70,
    'attendance_mark':     45,   # all teachers
    'attendance_view_all': 70,
    'teacher_assign':      70,

    # Finance
    'finance_view_own_student': 45,  # teachers see fee status only
    'finance_view':        80,   # bursar+
    'finance_manage':      80,
    'finance_delete':      90,
    'expense_approve':     80,

    # Communication
    'announcement_view':   20,
    'announcement_create': 60,   # teachers+ can create
    'announcement_manage': 70,   # admin+ can edit/delete others
    'sms_send':            60,   # teachers+ (class parents only)
    'sms_view_all':        70,

    # Staff
    'staff_view':          70,
    'staff_manage':        80,
    'staff_delete':        90,
    'leave_own':           20,   # everyone can manage own leave
    'leave_approve':       80,
    'staff_attendance_mark': 80,

    # Reports
    'report_academic':     60,
    'report_attendance':   60,
    'report_financial':    80,
    'report_custom':       80,

    # Admin
    'django_admin':        90,
    'import_export':       70,
}

SUPPORT_ROLES = {'driver', 'cleaner', 'canteen', 'security', 'support', 'other'}
TEACHER_ROLES = {'teacher', 'class_teacher', 'subject_teacher', 'assistant_teacher'}
MANAGEMENT_ROLES = {'proprietor', 'head_master', 'head_mistress', 'admin', 'bursar'}


def get_role_level(user):
    if user.is_superuser:
        return 999
    if hasattr(user, 'staff_profile') and user.staff_profile:
        return ROLE_HIERARCHY.get(user.staff_profile.role, 0)
    return 0


def can(user, action):
    """Check if user can perform action."""
    return get_role_level(user) >= PERM.get(action, 999)


def is_support_only(user):
    if user.is_superuser: return False
    if not hasattr(user, 'staff_profile'): return False
    return user.staff_profile.role in SUPPORT_ROLES


def is_teacher(user):
    if not hasattr(user, 'staff_profile'): return False
    return user.staff_profile.role in TEACHER_ROLES


# ── MIXINS ──────────────────────────────────────────────────────

class RoleRequiredMixin(LoginRequiredMixin):
    """Base mixin — set required_level or required_roles on the view."""
    required_level = 0
    required_roles = None  # optional list of exact role strings
    permission_denied_message = "You don't have permission to access this page."

    def dispatch(self, request, *args, **kwargs):
        response = super().dispatch(request, *args, **kwargs)
        # LoginRequiredMixin may have redirected already
        if not request.user.is_authenticated:
            return response

        level = get_role_level(request.user)

        if self.required_roles:
            if not request.user.is_superuser:
                role = getattr(getattr(request.user, 'staff_profile', None), 'role', None)
                if role not in self.required_roles:
                    return self._deny(request)

        elif level < self.required_level:
            return self._deny(request)

        return super(LoginRequiredMixin, self).dispatch(request, *args, **kwargs)

    def _deny(self, request):
        messages.error(request, self.permission_denied_message)
        if request.headers.get('x-requested-with') == 'XMLHttpRequest':
            from django.http import JsonResponse
            return JsonResponse({'error': self.permission_denied_message}, status=403)
        return redirect('staff:staff_dashboard')


class ManagementRequiredMixin(RoleRequiredMixin):
    required_level = 70
    permission_denied_message = "Only administrators and above can do this."


class HeadRequiredMixin(RoleRequiredMixin):
    required_level = 90
    permission_denied_message = "Only the Head Teacher or Proprietor can do this."


class BursarRequiredMixin(RoleRequiredMixin):
    required_level = 80
    permission_denied_message = "Finance access is restricted to the Bursar and above."


class TeacherRequiredMixin(RoleRequiredMixin):
    required_level = 45
    permission_denied_message = "This area is for teaching staff only."


class SupportDashboardMixin(LoginRequiredMixin):
    """Redirect support-only staff to their limited dashboard."""
    def dispatch(self, request, *args, **kwargs):
        if not request.user.is_authenticated:
            return redirect('staff:login')
        if is_support_only(request.user):
            from django.urls import reverse
            if request.path != reverse('staff:staff_dashboard'):
                messages.info(request, "Your account has limited access.")
                return redirect('staff:staff_dashboard')
        return super().dispatch(request, *args, **kwargs)
