"""
Enhanced notification views for intelligent routing and management
"""
from django.shortcuts import render, get_object_or_404, redirect
from django.contrib.auth.decorators import login_required
from django.http import JsonResponse
from django.contrib import messages
from django.core.paginator import Paginator
from django.db.models import Q, Count
from django.utils import timezone
from django.views.decorators.http import require_http_methods
from django.contrib.auth import get_user_model
from .models import Notification
from .notification_models import (
    NotificationPreference, NotificationRule, NotificationTemplate,
    NotificationDelivery, NotificationEscalation, NotificationBatch
)
from .notification_routing_service import NotificationRoutingService, NotificationPreferenceService
from users.decorators import role_required, module_access_required
import json
from datetime import datetime, timedelta

User = get_user_model()


@login_required
def notification_preferences(request):
    """Manage user notification preferences"""
    preference_service = NotificationPreferenceService()
    
    if request.method == 'POST':
        try:
            preferences_data = json.loads(request.body)
            preference_service.update_user_preferences(request.user, preferences_data)
            return JsonResponse({'status': 'success', 'message': 'Preferences updated successfully'})
        except Exception as e:
            return JsonResponse({'status': 'error', 'message': str(e)})
    
    # Get current preferences
    preferences = preference_service.get_user_preferences(request.user)
    
    # Get available notification types
    notification_types = [choice[0] for choice in Notification.NOTIFICATION_TYPES]
    channels = ['in_app', 'email', 'sms', 'push']
    
    context = {
        'preferences': preferences,
        'notification_types': notification_types,
        'channels': channels,
        'frequency_choices': NotificationPreference.FREQUENCY_CHOICES,
    }
    
    return render(request, 'utils/notification_preferences.html', context)


@login_required
@role_required(['admin', 'team_leader'])
def notification_rules(request):
    """Manage notification routing rules"""
    if request.method == 'POST':
        try:
            data = json.loads(request.body)
            action = data.get('action')
            
            if action == 'create':
                rule = NotificationRule.objects.create(
                    name=data['name'],
                    description=data.get('description', ''),
                    notification_type=data['notification_type'],
                    condition_type=data['condition_type'],
                    condition_field=data['condition_field'],
                    operator=data['operator'],
                    condition_value=data['condition_value'],
                    target_roles=data.get('target_roles', []),
                    escalation_delay=data.get('escalation_delay', 0),
                    escalation_roles=data.get('escalation_roles', []),
                    priority=data.get('priority', 1)
                )
                return JsonResponse({'status': 'success', 'rule_id': str(rule.id)})
            
            elif action == 'update':
                rule = get_object_or_404(NotificationRule, id=data['rule_id'])
                for field in ['name', 'description', 'condition_field', 'operator', 
                             'condition_value', 'target_roles', 'escalation_delay', 
                             'escalation_roles', 'priority']:
                    if field in data:
                        setattr(rule, field, data[field])
                rule.save()
                return JsonResponse({'status': 'success'})
            
            elif action == 'delete':
                rule = get_object_or_404(NotificationRule, id=data['rule_id'])
                rule.delete()
                return JsonResponse({'status': 'success'})
            
            elif action == 'toggle':
                rule = get_object_or_404(NotificationRule, id=data['rule_id'])
                rule.is_active = not rule.is_active
                rule.save()
                return JsonResponse({'status': 'success', 'is_active': rule.is_active})
                
        except Exception as e:
            return JsonResponse({'status': 'error', 'message': str(e)})
    
    # Get rules with pagination
    rules = NotificationRule.objects.all().order_by('priority', 'name')
    
    # Apply filters
    notification_type = request.GET.get('type')
    if notification_type:
        rules = rules.filter(notification_type=notification_type)
    
    is_active = request.GET.get('active')
    if is_active:
        rules = rules.filter(is_active=is_active.lower() == 'true')
    
    paginator = Paginator(rules, 20)
    page = request.GET.get('page')
    rules_page = paginator.get_page(page)
    
    context = {
        'rules': rules_page,
        'notification_types': [choice[0] for choice in Notification.NOTIFICATION_TYPES],
        'condition_types': NotificationRule.CONDITION_TYPES,
        'operators': NotificationRule.OPERATOR_CHOICES,
        'role_choices': User.ROLE_CHOICES,
        'selected_type': notification_type,
        'selected_active': is_active,
    }
    
    return render(request, 'utils/notification_rules.html', context)


@login_required
@role_required(['admin', 'team_leader'])
def notification_templates(request):
    """Manage notification templates"""
    if request.method == 'POST':
        try:
            data = json.loads(request.body)
            action = data.get('action')
            
            if action == 'create':
                template = NotificationTemplate.objects.create(
                    name=data['name'],
                    notification_type=data['notification_type'],
                    channel=data['channel'],
                    subject_template=data.get('subject_template', ''),
                    title_template=data['title_template'],
                    message_template=data['message_template'],
                    html_template=data.get('html_template', ''),
                    variables=data.get('variables', {}),
                    is_default=data.get('is_default', False)
                )
                return JsonResponse({'status': 'success', 'template_id': str(template.id)})
            
            elif action == 'update':
                template = get_object_or_404(NotificationTemplate, id=data['template_id'])
                for field in ['name', 'subject_template', 'title_template', 
                             'message_template', 'html_template', 'variables', 'is_default']:
                    if field in data:
                        setattr(template, field, data[field])
                template.save()
                return JsonResponse({'status': 'success'})
            
            elif action == 'delete':
                template = get_object_or_404(NotificationTemplate, id=data['template_id'])
                template.delete()
                return JsonResponse({'status': 'success'})
            
            elif action == 'preview':
                template = get_object_or_404(NotificationTemplate, id=data['template_id'])
                context = data.get('context', {})
                rendered = template.render(context)
                return JsonResponse({'status': 'success', 'rendered': rendered})
                
        except Exception as e:
            return JsonResponse({'status': 'error', 'message': str(e)})
    
    # Get templates with pagination
    templates = NotificationTemplate.objects.all().order_by('notification_type', 'channel', 'name')
    
    # Apply filters
    notification_type = request.GET.get('type')
    if notification_type:
        templates = templates.filter(notification_type=notification_type)
    
    channel = request.GET.get('channel')
    if channel:
        templates = templates.filter(channel=channel)
    
    paginator = Paginator(templates, 20)
    page = request.GET.get('page')
    templates_page = paginator.get_page(page)
    
    context = {
        'templates': templates_page,
        'notification_types': [choice[0] for choice in Notification.NOTIFICATION_TYPES],
        'channels': NotificationTemplate.CHANNEL_CHOICES,
        'selected_type': notification_type,
        'selected_channel': channel,
    }
    
    return render(request, 'utils/notification_templates.html', context)


@login_required
@role_required(['admin', 'team_leader'])
def notification_analytics(request):
    """View notification analytics and delivery statistics"""
    # Get date range
    days = int(request.GET.get('days', 30))
    start_date = timezone.now() - timedelta(days=days)
    
    # Overall statistics
    total_notifications = Notification.objects.filter(created_at__gte=start_date).count()
    total_deliveries = NotificationDelivery.objects.filter(created_at__gte=start_date).count()
    
    # Delivery statistics by channel
    delivery_stats = {}
    for channel, _ in NotificationTemplate.CHANNEL_CHOICES:
        channel_deliveries = NotificationDelivery.objects.filter(
            channel=channel,
            created_at__gte=start_date
        )
        
        delivery_stats[channel] = {
            'total': channel_deliveries.count(),
            'sent': channel_deliveries.filter(status='sent').count(),
            'delivered': channel_deliveries.filter(status='delivered').count(),
            'read': channel_deliveries.filter(status='read').count(),
            'failed': channel_deliveries.filter(status='failed').count(),
        }
    
    # Notification type statistics
    type_stats = (
        Notification.objects.filter(created_at__gte=start_date)
        .values('notification_type')
        .annotate(count=Count('id'))
        .order_by('-count')[:10]
    )
    
    # User engagement statistics
    user_stats = (
        Notification.objects.filter(created_at__gte=start_date)
        .values('user__role')
        .annotate(
            total=Count('id'),
            read=Count('id', filter=Q(read_at__isnull=False))
        )
        .order_by('-total')
    )
    
    # Escalation statistics
    escalation_stats = {
        'total': NotificationEscalation.objects.filter(escalated_at__gte=start_date).count(),
        'acknowledged': NotificationEscalation.objects.filter(
            escalated_at__gte=start_date,
            acknowledged_at__isnull=False
        ).count(),
        'resolved': NotificationEscalation.objects.filter(
            escalated_at__gte=start_date,
            resolved_at__isnull=False
        ).count(),
    }
    
    # Recent escalations
    recent_escalations = NotificationEscalation.objects.filter(
        escalated_at__gte=start_date
    ).select_related('original_notification', 'escalated_to', 'rule').order_by('-escalated_at')[:10]
    
    context = {
        'days': days,
        'total_notifications': total_notifications,
        'total_deliveries': total_deliveries,
        'delivery_stats': delivery_stats,
        'type_stats': type_stats,
        'user_stats': user_stats,
        'escalation_stats': escalation_stats,
        'recent_escalations': recent_escalations,
    }
    
    return render(request, 'utils/notification_analytics.html', context)


@login_required
def notification_escalations(request):
    """View and manage notification escalations"""
    if request.method == 'POST':
        try:
            data = json.loads(request.body)
            action = data.get('action')
            escalation_id = data.get('escalation_id')
            
            escalation = get_object_or_404(NotificationEscalation, id=escalation_id)
            
            if action == 'acknowledge':
                escalation.acknowledge(data.get('notes', ''))
                return JsonResponse({'status': 'success'})
            
            elif action == 'resolve':
                escalation.resolve(data.get('notes', ''))
                return JsonResponse({'status': 'success'})
                
        except Exception as e:
            return JsonResponse({'status': 'error', 'message': str(e)})
    
    # Get escalations for current user or all if admin
    if request.user.role in ['admin', 'team_leader']:
        escalations = NotificationEscalation.objects.all()
    else:
        escalations = NotificationEscalation.objects.filter(escalated_to=request.user)
    
    # Apply filters
    status = request.GET.get('status')
    if status == 'pending':
        escalations = escalations.filter(acknowledged_at__isnull=True, resolved_at__isnull=True)
    elif status == 'acknowledged':
        escalations = escalations.filter(acknowledged_at__isnull=False, resolved_at__isnull=True)
    elif status == 'resolved':
        escalations = escalations.filter(resolved_at__isnull=False)
    
    escalations = escalations.select_related(
        'original_notification', 'escalated_to', 'rule'
    ).order_by('-escalated_at')
    
    paginator = Paginator(escalations, 20)
    page = request.GET.get('page')
    escalations_page = paginator.get_page(page)
    
    context = {
        'escalations': escalations_page,
        'selected_status': status,
    }
    
    return render(request, 'utils/notification_escalations.html', context)


@login_required
@role_required(['admin', 'team_leader'])
def notification_batch_management(request):
    """Manage batch notifications"""
    if request.method == 'POST':
        try:
            data = json.loads(request.body)
            action = data.get('action')
            
            if action == 'create':
                template = get_object_or_404(NotificationTemplate, id=data['template_id'])
                
                batch = NotificationBatch.objects.create(
                    name=data['name'],
                    notification_type=data['notification_type'],
                    template=template,
                    target_criteria=data['target_criteria'],
                    scheduled_at=data.get('scheduled_at'),
                    created_by=request.user
                )
                
                # Calculate recipient count
                recipients = _get_batch_recipients(data['target_criteria'])
                batch.total_recipients = len(recipients)
                batch.save()
                
                return JsonResponse({'status': 'success', 'batch_id': str(batch.id)})
            
            elif action == 'start':
                batch = get_object_or_404(NotificationBatch, id=data['batch_id'])
                if batch.status == 'pending':
                    # Start processing (this would typically be handled by a background task)
                    _process_notification_batch(batch)
                    return JsonResponse({'status': 'success'})
                else:
                    return JsonResponse({'status': 'error', 'message': 'Batch is not in pending status'})
            
            elif action == 'cancel':
                batch = get_object_or_404(NotificationBatch, id=data['batch_id'])
                if batch.status in ['pending', 'processing']:
                    batch.status = 'cancelled'
                    batch.save()
                    return JsonResponse({'status': 'success'})
                else:
                    return JsonResponse({'status': 'error', 'message': 'Cannot cancel completed batch'})
                    
        except Exception as e:
            return JsonResponse({'status': 'error', 'message': str(e)})
    
    # Get batches
    batches = NotificationBatch.objects.all().order_by('-created_at')
    
    # Apply filters
    status = request.GET.get('status')
    if status:
        batches = batches.filter(status=status)
    
    paginator = Paginator(batches, 20)
    page = request.GET.get('page')
    batches_page = paginator.get_page(page)
    
    # Get templates for creating new batches
    templates = NotificationTemplate.objects.filter(is_active=True).order_by('notification_type', 'name')
    
    context = {
        'batches': batches_page,
        'templates': templates,
        'notification_types': [choice[0] for choice in Notification.NOTIFICATION_TYPES],
        'role_choices': User.ROLE_CHOICES,
        'selected_status': status,
    }
    
    return render(request, 'utils/notification_batch_management.html', context)


def _get_batch_recipients(criteria):
    """Get recipients based on batch criteria"""
    users = User.objects.filter(is_active=True)
    
    if 'roles' in criteria:
        users = users.filter(role__in=criteria['roles'])
    
    if 'branches' in criteria:
        users = users.filter(branch_id__in=criteria['branches'])
    
    if 'portfolio_managers' in criteria:
        users = users.filter(portfolio_manager_id__in=criteria['portfolio_managers'])
    
    return list(users)


def _process_notification_batch(batch):
    """Process a notification batch (simplified version)"""
    try:
        batch.start_processing()
        
        recipients = _get_batch_recipients(batch.target_criteria)
        routing_service = NotificationRoutingService()
        
        success_count = 0
        failed_count = 0
        
        for recipient in recipients:
            try:
                # Create notification for each recipient
                context = {
                    'user': recipient,
                    'batch': batch,
                }
                
                notifications = routing_service.route_notification(
                    batch.notification_type,
                    context,
                    priority='medium'
                )
                
                if notifications:
                    success_count += 1
                else:
                    failed_count += 1
                    
            except Exception as e:
                failed_count += 1
                batch.error_log += f"Failed for user {recipient.id}: {str(e)}\n"
        
        batch.sent_count = success_count
        batch.failed_count = failed_count
        batch.complete_processing()
        
    except Exception as e:
        batch.fail_processing(str(e))


@login_required
@require_http_methods(["POST"])
def test_notification_routing(request):
    """Test notification routing with sample data"""
    try:
        data = json.loads(request.body)
        
        routing_service = NotificationRoutingService()
        
        # Create test context
        context = {
            'user': request.user,
            'title': data.get('title', 'Test Notification'),
            'message': data.get('message', 'This is a test notification'),
            'action_url': data.get('action_url'),
        }
        
        notifications = routing_service.route_notification(
            data.get('notification_type', 'system_maintenance'),
            context,
            priority=data.get('priority', 'medium')
        )
        
        return JsonResponse({
            'status': 'success',
            'message': f'Created {len(notifications)} test notifications',
            'notification_ids': [str(n.id) for n in notifications]
        })
        
    except Exception as e:
        return JsonResponse({'status': 'error', 'message': str(e)})