# -*- coding: utf-8 -*-
"""
Django Permission System for Channels App

This module provides a comprehensive permission system for the channels app
with decorators, mixins, and utility functions for checking user permissions.
"""

from functools import wraps
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.core.exceptions import PermissionDenied
from django.http import JsonResponse
from django.shortcuts import redirect
from django.contrib import messages
from django.urls import reverse_lazy
from django.utils.decorators import method_decorator


class ChannelPermissionRequiredMixin(LoginRequiredMixin):
    """
    Mixin that checks if user has required channel permissions.
    Can be used with class-based views.
    """
    permission_required = None
    permission_denied_message = "You don't have permission to access this page."
    
    def dispatch(self, request, *args, **kwargs):
        if not self.has_permission():
            if request.is_ajax():
                return JsonResponse({
                    'success': False,
                    'message': self.permission_denied_message
                }, status=403)
            else:
                messages.error(request, self.permission_denied_message)
                return redirect('core:dashboard')
        return super().dispatch(request, *args, **kwargs)
    
    def has_permission(self):
        """Check if user has required permissions."""
        if not self.permission_required:
            return True
        
        if isinstance(self.permission_required, str):
            permissions = [self.permission_required]
        else:
            permissions = self.permission_required
        
        return self.request.user.has_perms(permissions)


def channel_permission_required(permission_codename, login_url=None, raise_exception=False):
    """
    Decorator for views that checks whether a user has permission to access the view.
    
    Args:
        permission_codename: String or list of permission codenames to check
        login_url: URL to redirect to if user is not authenticated
        raise_exception: Whether to raise PermissionDenied exception
    """
    def decorator(view_func):
        @wraps(view_func)
        @login_required(login_url=login_url)
        def _wrapped_view(request, *args, **kwargs):
            if isinstance(permission_codename, str):
                permissions = [permission_codename]
            else:
                permissions = permission_codename
            
            if not request.user.has_perms(permissions):
                if raise_exception:
                    raise PermissionDenied
                
                if request.is_ajax():
                    return JsonResponse({
                        'success': False,
                        'message': "You don't have permission to perform this action."
                    }, status=403)
                else:
                    messages.error(request, "You don't have permission to perform this action.")
                    return redirect('core:dashboard')
            
            return view_func(request, *args, **kwargs)
        return _wrapped_view
    return decorator


class ChannelManagementPermissions:
    """Permission constants for channel management."""
    
    # Channel permissions
    CAN_VIEW_CHANNELS = 'channels.view_channel'
    CAN_ADD_CHANNELS = 'channels.add_channel'
    CAN_CHANGE_CHANNELS = 'channels.change_channel'
    CAN_DELETE_CHANNELS = 'channels.delete_channel'
    
    # Channel Zone permissions
    CAN_VIEW_ZONES = 'channels.view_channelzone'
    CAN_ADD_ZONES = 'channels.add_channelzone'
    CAN_CHANGE_ZONES = 'channels.change_channelzone'
    CAN_DELETE_ZONES = 'channels.delete_channelzone'
    
    # Channel Codec permissions
    CAN_VIEW_CODECS = 'channels.view_channelcodec'
    CAN_ADD_CODECS = 'channels.add_channelcodec'
    CAN_CHANGE_CODECS = 'channels.change_channelcodec'
    CAN_DELETE_CODECS = 'channels.delete_channelcodec'
    
    # EPG Program permissions
    CAN_VIEW_EPG = 'channels.view_epgprogram'
    CAN_ADD_EPG = 'channels.add_epgprogram'
    CAN_CHANGE_EPG = 'channels.change_epgprogram'
    CAN_DELETE_EPG = 'channels.delete_epgprogram'
    
    # Jingle permissions
    CAN_VIEW_JINGLES = 'channels.view_jingle'
    CAN_ADD_JINGLES = 'channels.add_jingle'
    CAN_CHANGE_JINGLES = 'channels.change_jingle'
    CAN_DELETE_JINGLES = 'channels.delete_jingle'
    
    # Schedule permissions
    CAN_VIEW_SCHEDULES = 'channels.view_channelschedule'
    CAN_ADD_SCHEDULES = 'channels.add_channelschedule'
    CAN_CHANGE_SCHEDULES = 'channels.change_channelschedule'
    CAN_DELETE_SCHEDULES = 'channels.delete_channelschedule'


def has_channel_management_permission(user):
    """Check if user has any channel management permissions."""
    return user.has_perms([
        ChannelManagementPermissions.CAN_VIEW_CHANNELS,
        ChannelManagementPermissions.CAN_ADD_CHANNELS,
        ChannelManagementPermissions.CAN_CHANGE_CHANNELS,
    ])


def has_channel_zone_permission(user):
    """Check if user has any channel zone permissions."""
    return user.has_perms([
        ChannelManagementPermissions.CAN_VIEW_ZONES,
        ChannelManagementPermissions.CAN_ADD_ZONES,
        ChannelManagementPermissions.CAN_CHANGE_ZONES,
    ])


def has_epg_management_permission(user):
    """Check if user has any EPG management permissions."""
    return user.has_perms([
        ChannelManagementPermissions.CAN_VIEW_EPG,
        ChannelManagementPermissions.CAN_ADD_EPG,
        ChannelManagementPermissions.CAN_CHANGE_EPG,
    ])


def create_channel_permissions():
    """
    Create custom permissions for the channels app.
    This should be called during app initialization.
    """
    from django.contrib.auth.models import Permission
    from django.contrib.contenttypes.models import ContentType
    from .models import Channel, ChannelZone, ChannelCodec, EPGProgram, Jingle, ChannelSchedule
    
    # Custom permissions that don't exist by default
    custom_permissions = [
        # Channel management
        ('can_manage_channels', 'Can manage all channels'),
        ('can_monitor_channels', 'Can monitor channel status'),
        ('can_export_channels', 'Can export channel data'),
        
        # Zone management
        ('can_manage_zones', 'Can manage channel zones'),
        ('can_configure_zones', 'Can configure zone settings'),
        
        # EPG management
        ('can_manage_epg', 'Can manage EPG programs'),
        ('can_import_epg', 'Can import EPG data'),
        
        # Jingle management
        ('can_upload_jingles', 'Can upload jingles'),
        ('can_detect_jingles', 'Can detect jingles in streams'),
        
        # Schedule management
        ('can_manage_schedules', 'Can manage channel schedules'),
        ('can_broadcast_control', 'Can control broadcasting'),
    ]
    
    # Create custom permissions
    for codename, name in custom_permissions:
        content_type = ContentType.objects.get_for_model(Channel)
        permission, created = Permission.objects.get_or_create(
            codename=codename,
            name=name,
            content_type=content_type
        )
        if created:
            print(f"Created permission: {codename}")


def setup_channel_roles():
    """
    Set up default roles for channel management.
    """
    from django.contrib.auth.models import Permission
    from apps.accounts.models import Role
    
    # Define default roles and their permissions
    default_roles = {
        'channel_admin': {
            'name': 'Channel Administrator',
            'description': 'Full access to channel management',
            'permissions': [
                'channels.add_channel', 'channels.change_channel', 'channels.delete_channel', 'channels.view_channel',
                'channels.add_channelzone', 'channels.change_channelzone', 'channels.delete_channelzone', 'channels.view_channelzone',
                'channels.add_channelcodec', 'channels.change_channelcodec', 'channels.delete_channelcodec', 'channels.view_channelcodec',
                'channels.add_epgprogram', 'channels.change_epgprogram', 'channels.delete_epgprogram', 'channels.view_epgprogram',
                'channels.add_jingle', 'channels.change_jingle', 'channels.delete_jingle', 'channels.view_jingle',
                'channels.add_channelschedule', 'channels.change_channelschedule', 'channels.delete_channelschedule', 'channels.view_channelschedule',
                'channels.can_manage_channels', 'channels.can_monitor_channels', 'channels.can_export_channels',
                'channels.can_manage_zones', 'channels.can_configure_zones', 'channels.can_manage_epg', 'channels.can_import_epg',
                'channels.can_upload_jingles', 'channels.can_detect_jingles', 'channels.can_manage_schedules', 'channels.can_broadcast_control',
            ]
        },
        'channel_manager': {
            'name': 'Channel Manager',
            'description': 'Can manage channels and EPG',
            'permissions': [
                'channels.add_channel', 'channels.change_channel', 'channels.view_channel',
                'channels.view_channelzone', 'channels.view_channelcodec',
                'channels.add_epgprogram', 'channels.change_epgprogram', 'channels.view_epgprogram',
                'channels.add_jingle', 'channels.change_jingle', 'channels.view_jingle',
                'channels.view_channelschedule', 'channels.can_manage_channels', 'channels.can_monitor_channels',
                'channels.can_manage_epg', 'channels.can_upload_jingles',
            ]
        },
        'channel_operator': {
            'name': 'Channel Operator',
            'description': 'Can view and monitor channels',
            'permissions': [
                'channels.view_channel', 'channels.view_channelzone', 'channels.view_channelcodec',
                'channels.view_epgprogram', 'channels.view_jingle', 'channels.view_channelschedule',
                'channels.can_monitor_channels',
            ]
        }
    }
    
    for role_code, role_data in default_roles.items():
        role, created = Role.objects.get_or_create(
            code=role_code,
            defaults={
                'name': role_data['name'],
                'description': role_data['description'],
                'role_type': 'system',
                'level': 2 if role_code == 'channel_admin' else 3 if role_code == 'channel_manager' else 4,
                'is_active': True,
                'is_default': False
            }
        )
        
        if created:
            print(f"Created role: {role_code}")
            
            # Add permissions to role
            permissions = Permission.objects.filter(codename__in=[
                perm.split('.')[-1] for perm in role_data['permissions']
            ])
            role.permissions.set(permissions)
            print(f"Added {permissions.count()} permissions to {role_code}")
