"""
Views for monitoring and managing permission cache performance
"""
from django.shortcuts import render, redirect
from django.contrib.admin.views.decorators import staff_member_required
from django.contrib import messages
from django.http import JsonResponse
from django.utils import timezone
from django.views.decorators.http import require_http_methods
from django.views.decorators.csrf import csrf_exempt
from users.permission_cache_service import permission_cache
from users.models import CustomUser
from users.decorators import require_permission
import json
import logging

logger = logging.getLogger(__name__)


@staff_member_required
@require_permission('admin', 'system_monitoring')
def cache_performance_dashboard(request):
    """
    Display cache performance dashboard with statistics and controls
    """
    try:
        # Get cache statistics
        cache_stats = permission_cache.get_cache_statistics()
        
        # Get recent cache activity (if available)
        recent_activity = _get_recent_cache_activity()
        
        # Get system recommendations
        recommendations = _get_cache_recommendations(cache_stats)
        
        context = {
            'cache_stats': cache_stats,
            'recent_activity': recent_activity,
            'recommendations': recommendations,
            'page_title': 'Permission Cache Performance',
            'last_updated': timezone.now()
        }
        
        return render(request, 'users/cache_performance_dashboard.html', context)
        
    except Exception as e:
        logger.error(f"Error loading cache performance dashboard: {e}")
        messages.error(request, f"Error loading cache dashboard: {str(e)}")
        return redirect('admin:index')


@staff_member_required
@require_permission('admin', 'cache_management')
@require_http_methods(["POST"])
def warm_cache_action(request):
    """
    Warm cache for selected users or roles
    """
    try:
        action_type = request.POST.get('action_type')
        
        if action_type == 'critical_users':
            limit = int(request.POST.get('limit', 50))
            results = permission_cache.warm_critical_users_cache(limit)
            
            messages.success(
                request, 
                f"Cache warmed for {results['successful_users']}/{results['total_users']} critical users"
            )
            
        elif action_type == 'specific_users':
            user_ids = request.POST.getlist('user_ids')
            if not user_ids:
                messages.error(request, "No users selected for cache warming")
                return redirect('cache_performance_dashboard')
            
            total_successful = 0
            total_failed = 0
            
            for user_id in user_ids:
                try:
                    results = permission_cache.warm_user_cache(user_id)
                    if not results.get('errors'):
                        total_successful += 1
                    else:
                        total_failed += 1
                except Exception as e:
                    total_failed += 1
                    logger.error(f"Error warming cache for user {user_id}: {e}")
            
            messages.success(
                request,
                f"Cache warming completed: {total_successful} successful, {total_failed} failed"
            )
            
        elif action_type == 'role_users':
            role = request.POST.get('role')
            limit = int(request.POST.get('limit', 20))
            
            if not role:
                messages.error(request, "No role selected for cache warming")
                return redirect('cache_performance_dashboard')
            
            # Get users with this role
            users = CustomUser.objects.filter(role=role, is_active=True)[:limit]
            
            total_successful = 0
            total_failed = 0
            
            for user in users:
                try:
                    results = permission_cache.warm_user_cache(str(user.id))
                    if not results.get('errors'):
                        total_successful += 1
                    else:
                        total_failed += 1
                except Exception as e:
                    total_failed += 1
                    logger.error(f"Error warming cache for user {user.id}: {e}")
            
            messages.success(
                request,
                f"Cache warmed for {total_successful}/{len(users)} users with role '{role}'"
            )
        
        else:
            messages.error(request, "Invalid cache warming action")
        
        return redirect('cache_performance_dashboard')
        
    except Exception as e:
        logger.error(f"Error in cache warming action: {e}")
        messages.error(request, f"Error warming cache: {str(e)}")
        return redirect('cache_performance_dashboard')


@staff_member_required
@require_permission('admin', 'cache_management')
@require_http_methods(["POST"])
def invalidate_cache_action(request):
    """
    Invalidate cache for selected users or roles
    """
    try:
        action_type = request.POST.get('action_type')
        
        if action_type == 'specific_user':
            user_id = request.POST.get('user_id')
            page_name = request.POST.get('page_name')  # Optional
            
            if not user_id:
                messages.error(request, "No user selected for cache invalidation")
                return redirect('cache_performance_dashboard')
            
            invalidated_count = permission_cache.invalidate_user_cache(user_id, page_name)
            
            if page_name:
                messages.success(
                    request,
                    f"Invalidated {invalidated_count} cache keys for user {user_id}, page {page_name}"
                )
            else:
                messages.success(
                    request,
                    f"Invalidated {invalidated_count} cache keys for user {user_id} (all pages)"
                )
                
        elif action_type == 'role_cache':
            role = request.POST.get('role')
            
            if not role:
                messages.error(request, "No role selected for cache invalidation")
                return redirect('cache_performance_dashboard')
            
            invalidated_count = permission_cache.invalidate_role_cache(role)
            
            messages.success(
                request,
                f"Invalidated {invalidated_count} cache keys for role '{role}'"
            )
        
        else:
            messages.error(request, "Invalid cache invalidation action")
        
        return redirect('cache_performance_dashboard')
        
    except Exception as e:
        logger.error(f"Error in cache invalidation action: {e}")
        messages.error(request, f"Error invalidating cache: {str(e)}")
        return redirect('cache_performance_dashboard')


@staff_member_required
@require_http_methods(["GET"])
def cache_statistics_api(request):
    """
    API endpoint for real-time cache statistics
    """
    try:
        stats = permission_cache.get_cache_statistics()
        
        # Add additional runtime statistics
        stats['timestamp'] = timezone.now().isoformat()
        stats['server_time'] = timezone.now().strftime('%Y-%m-%d %H:%M:%S')
        
        return JsonResponse(stats)
        
    except Exception as e:
        logger.error(f"Error getting cache statistics: {e}")
        return JsonResponse({
            'error': str(e),
            'timestamp': timezone.now().isoformat()
        }, status=500)


@staff_member_required
@require_http_methods(["GET"])
def user_cache_status_api(request):
    """
    API endpoint to check cache status for specific users
    """
    try:
        user_ids = request.GET.getlist('user_ids')
        page_name = request.GET.get('page_name', 'loans')
        
        if not user_ids:
            return JsonResponse({'error': 'No user IDs provided'}, status=400)
        
        cache_status = {}
        
        for user_id in user_ids:
            try:
                # Check if user has cached permissions
                cached_permissions = permission_cache.get_user_page_permissions(user_id, page_name)
                cached_actions = permission_cache.get_user_available_actions(user_id, page_name)
                
                cache_status[user_id] = {
                    'has_permissions_cache': cached_permissions is not None,
                    'has_actions_cache': cached_actions is not None,
                    'permissions_count': len(cached_permissions) if cached_permissions else 0,
                    'actions_count': len(cached_actions) if cached_actions else 0
                }
                
            except Exception as e:
                cache_status[user_id] = {
                    'error': str(e),
                    'has_permissions_cache': False,
                    'has_actions_cache': False
                }
        
        return JsonResponse({
            'cache_status': cache_status,
            'page_name': page_name,
            'timestamp': timezone.now().isoformat()
        })
        
    except Exception as e:
        logger.error(f"Error checking user cache status: {e}")
        return JsonResponse({
            'error': str(e),
            'timestamp': timezone.now().isoformat()
        }, status=500)


def _get_recent_cache_activity():
    """
    Get recent cache activity information
    """
    try:
        # This would typically come from cache logs or monitoring
        # For now, return placeholder data
        return {
            'recent_hits': 0,
            'recent_misses': 0,
            'recent_invalidations': 0,
            'top_cached_pages': ['loans', 'clients', 'reports'],
            'most_active_users': []
        }
    except Exception as e:
        logger.error(f"Error getting recent cache activity: {e}")
        return {}


def _get_cache_recommendations(cache_stats):
    """
    Generate cache optimization recommendations based on statistics
    """
    recommendations = []
    
    try:
        hit_rate = cache_stats.get('hit_rate_percentage', 0)
        total_requests = cache_stats.get('total_hits', 0) + cache_stats.get('total_misses', 0)
        
        # Hit rate recommendations
        if hit_rate < 70:
            recommendations.append({
                'type': 'warning',
                'title': 'Low Cache Hit Rate',
                'message': f'Current hit rate is {hit_rate:.1f}%. Consider warming cache for active users.',
                'action': 'warm_critical_users'
            })
        elif hit_rate > 90:
            recommendations.append({
                'type': 'success',
                'title': 'Excellent Cache Performance',
                'message': f'Cache hit rate is {hit_rate:.1f}%. Performance is optimal.',
                'action': None
            })
        
        # Request volume recommendations
        if total_requests > 10000:
            recommendations.append({
                'type': 'info',
                'title': 'High Cache Usage',
                'message': f'{total_requests} total cache requests. Consider monitoring Redis memory usage.',
                'action': 'monitor_memory'
            })
        
        # Backend recommendations
        cache_backend = cache_stats.get('cache_backend', 'Unknown')
        if cache_backend != 'Redis':
            recommendations.append({
                'type': 'warning',
                'title': 'Cache Backend Optimization',
                'message': f'Currently using {cache_backend}. Redis is recommended for better performance.',
                'action': 'upgrade_backend'
            })
        
        # Redis-specific recommendations
        redis_stats = cache_stats.get('redis_stats', {})
        if redis_stats:
            used_memory = redis_stats.get('used_memory', 'N/A')
            if used_memory != 'N/A' and 'MB' in used_memory:
                try:
                    memory_mb = float(used_memory.replace('MB', ''))
                    if memory_mb > 100:
                        recommendations.append({
                            'type': 'info',
                            'title': 'Redis Memory Usage',
                            'message': f'Redis is using {used_memory}. Monitor for memory optimization opportunities.',
                            'action': 'optimize_memory'
                        })
                except:
                    pass
        
        return recommendations
        
    except Exception as e:
        logger.error(f"Error generating cache recommendations: {e}")
        return [{
            'type': 'error',
            'title': 'Recommendation Error',
            'message': f'Could not generate recommendations: {str(e)}',
            'action': None
        }]