"""
Система гранулярных прав доступа.

Определяет все доступные разрешения и функции для их проверки.
"""
from functools import wraps
from django.http import JsonResponse, HttpResponseForbidden
from django.shortcuts import redirect
from django.contrib import messages


# Определение всех разрешений в системе
# Формат: (код, название, описание)
PERMISSIONS = [
    # Source List Page - Toolbar buttons
    ('source_create', 'Создание источника', 'Кнопка "Создать" на странице списка источников'),
    ('source_edit', 'Редактирование источника', 'Кнопка редактирования источника'),
    ('source_delete', 'Удаление источников', 'Кнопка "Удалить" на странице списка источников'),
    ('source_import_excel', 'Импорт из Excel', 'Кнопка "Excel" для загрузки данных'),
    ('source_import_csv', 'Импорт из CSV', 'Кнопка "CSV" для загрузки данных'),
    ('source_averaging', 'Усреднение точек', 'Кнопка "Усреднение" на странице списка источников'),
    ('source_tech_analyze', 'Технический анализ', 'Кнопка "Тех. анализ" на странице списка источников'),
    ('source_merge', 'Объединение источников', 'Кнопка "Объединить" в offcanvas списка'),
    
    # Source Requests
    ('request_create', 'Создание заявки', 'Создание новой заявки на источник'),
    ('request_edit', 'Редактирование заявки', 'Редактирование существующей заявки'),
    ('request_delete', 'Удаление заявки', 'Удаление заявки на источник'),
    ('request_import', 'Импорт заявок', 'Импорт заявок из файла'),
    
    # ObjItem (Points)
    ('objitem_create', 'Создание точки', 'Создание новой точки ГЛ'),
    ('objitem_edit', 'Редактирование точки', 'Редактирование точки ГЛ'),
    ('objitem_delete', 'Удаление точки', 'Удаление точки ГЛ'),
    
    # Satellites
    ('satellite_create', 'Создание спутника', 'Создание нового спутника'),
    ('satellite_edit', 'Редактирование спутника', 'Редактирование спутника'),
    ('satellite_delete', 'Удаление спутника', 'Удаление спутника'),
    
    # Tech Analyze
    ('tech_analyze_create', 'Создание тех. анализа', 'Создание записи технического анализа'),
    ('tech_analyze_edit', 'Редактирование тех. анализа', 'Редактирование записи технического анализа'),
    ('tech_analyze_delete', 'Удаление тех. анализа', 'Удаление записи технического анализа'),
    
    # Signal Marks
    ('mark_create', 'Создание отметки', 'Создание отметки о сигнале'),
    ('mark_edit', 'Редактирование отметки', 'Редактирование отметки о сигнале'),
    
    # Statistics
    ('statistics_view', 'Просмотр статистики', 'Доступ к странице статистики'),
    
    # Kubsat
    ('kubsat_view', 'Просмотр Кубсат', 'Доступ к странице Кубсат'),
    ('kubsat_edit', 'Редактирование Кубсат', 'Редактирование данных Кубсат'),
    
    # LyngSat
    ('lyngsat_parse', 'Парсинг LyngSat', 'Запуск парсинга LyngSat'),
    
    # Transponders
    ('transponder_create', 'Создание транспондера', 'Создание нового транспондера'),
    ('transponder_edit', 'Редактирование транспондера', 'Редактирование транспондера'),
    ('transponder_delete', 'Удаление транспондера', 'Удаление транспондера'),
    ('transponder_import_xml', 'Импорт транспондеров из XML', 'Загрузка транспондеров из XML файла'),
    
    # Errors Report (Журнал ошибок)
    ('errors_report_create', 'Создание записи журнала ошибок', 'Создание новой записи в журнале ошибок'),
    ('errors_report_edit', 'Редактирование записи журнала ошибок', 'Редактирование записи в журнале ошибок'),
    ('errors_report_delete', 'Удаление записи журнала ошибок', 'Удаление записи из журнала ошибок'),
    
    # Admin access
    # ('admin_access', 'Доступ к админ-панели', 'Доступ к административной панели Django'),
]

# Словарь для быстрого доступа к разрешениям
PERMISSION_CHOICES = [(code, name) for code, name, _ in PERMISSIONS]
PERMISSION_DESCRIPTIONS = {code: desc for code, _, desc in PERMISSIONS}

# Права по умолчанию для ролей
DEFAULT_ROLE_PERMISSIONS = {
    'admin': [code for code, _, _ in PERMISSIONS],  # Все права
    'moderator': [
        'source_create', 'source_edit', 'source_import_excel', 'source_import_csv',
        'source_averaging', 'source_tech_analyze', 'source_merge',
        'request_create', 'request_edit', 'request_import',
        'objitem_create', 'objitem_edit',
        'satellite_create', 'satellite_edit',
        'transponder_create', 'transponder_edit', 'transponder_import_xml',
        'tech_analyze_create', 'tech_analyze_edit',
        'mark_create', 'mark_edit',
        'statistics_view',
        'kubsat_view', 'kubsat_edit',
        'errors_report_create', 'errors_report_edit',
    ],
    'user': [
        'statistics_view',
        'kubsat_view',
    ],
}


def has_permission(user, permission_code):
    """
    Проверяет, имеет ли пользователь указанное разрешение.
    
    Args:
        user: Объект User Django
        permission_code: Код разрешения (строка)
    
    Returns:
        bool: True если пользователь имеет разрешение
    """
    if not user or not user.is_authenticated:
        return False
    
    # Суперпользователь имеет все права
    if user.is_superuser:
        return True
    
    # Получаем CustomUser
    custom_user = getattr(user, 'customuser', None)
    if not custom_user:
        return False
    
    # Проверяем, используются ли индивидуальные разрешения
    if custom_user.use_custom_permissions:
        # Используем индивидуальные разрешения
        return custom_user.user_permissions.filter(code=permission_code).exists()
    
    # Иначе используем права по умолчанию для роли
    role = custom_user.role
    default_perms = DEFAULT_ROLE_PERMISSIONS.get(role, [])
    return permission_code in default_perms


def get_user_permissions(user):
    """
    Возвращает список кодов разрешений пользователя.
    
    Args:
        user: Объект User Django
    
    Returns:
        list: Список кодов разрешений
    """
    if not user or not user.is_authenticated:
        return []
    
    if user.is_superuser:
        return [code for code, _, _ in PERMISSIONS]
    
    custom_user = getattr(user, 'customuser', None)
    if not custom_user:
        return []
    
    # Проверяем, используются ли индивидуальные разрешения
    if custom_user.use_custom_permissions:
        return list(custom_user.user_permissions.values_list('code', flat=True))
    
    # Права по умолчанию для роли
    return DEFAULT_ROLE_PERMISSIONS.get(custom_user.role, [])


def permission_required(permission_code, redirect_url=None, raise_exception=False):
    """
    Декоратор для проверки разрешения на уровне view.
    
    Args:
        permission_code: Код разрешения
        redirect_url: URL для редиректа при отсутствии прав (по умолчанию на предыдущую страницу)
        raise_exception: Если True, возвращает 403 вместо редиректа
    
    Usage:
        @permission_required('source_create')
        def my_view(request):
            ...
    """
    def decorator(view_func):
        @wraps(view_func)
        def wrapper(request, *args, **kwargs):
            if has_permission(request.user, permission_code):
                return view_func(request, *args, **kwargs)
            
            # Для AJAX запросов возвращаем JSON
            if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
                return JsonResponse({
                    'success': False,
                    'error': 'У вас нет прав для выполнения этого действия'
                }, status=403)
            
            if raise_exception:
                return HttpResponseForbidden('У вас нет прав для выполнения этого действия')
            
            messages.error(request, 'У вас нет прав для выполнения этого действия')
            
            if redirect_url:
                return redirect(redirect_url)
            
            # Редирект на предыдущую страницу или на главную
            referer = request.META.get('HTTP_REFERER')
            if referer:
                return redirect(referer)
            return redirect('mainapp:source_list')
        
        return wrapper
    return decorator


class PermissionRequiredMixin:
    """
    Миксин для class-based views для проверки разрешений.
    
    Usage:
        class MyView(PermissionRequiredMixin, View):
            permission_required = 'source_create'
            # или для нескольких разрешений (любое из них):
            permission_required = ['source_create', 'source_edit']
    """
    permission_required = None
    permission_denied_message = 'У вас нет прав для выполнения этого действия'
    
    def has_permission(self):
        """Проверяет наличие разрешения."""
        perms = self.get_permission_required()
        if isinstance(perms, str):
            return has_permission(self.request.user, perms)
        # Для списка - проверяем наличие хотя бы одного разрешения
        return any(has_permission(self.request.user, perm) for perm in perms)
    
    def get_permission_required(self):
        """Возвращает требуемое разрешение."""
        if self.permission_required is None:
            raise ValueError(
                f'{self.__class__.__name__} is missing the permission_required attribute.'
            )
        return self.permission_required
    
    def dispatch(self, request, *args, **kwargs):
        if not self.has_permission():
            return self.handle_no_permission()
        return super().dispatch(request, *args, **kwargs)
    
    def handle_no_permission(self):
        """Обработка отсутствия разрешения."""
        # Для AJAX запросов
        if self.request.headers.get('X-Requested-With') == 'XMLHttpRequest':
            return JsonResponse({
                'success': False,
                'error': self.permission_denied_message
            }, status=403)
        
        messages.error(self.request, self.permission_denied_message)
        
        referer = self.request.META.get('HTTP_REFERER')
        if referer:
            return redirect(referer)
        return redirect('mainapp:source_list')
