# -*- coding: utf-8 -*-
"""
Activities Views

This module defines class-based views for the activities app.
It provides views for displaying activity logs, audit trails,
and security events with proper authentication and permissions.

Views:
    - ActivityListView: List view for activities
    - ActivityDetailView: Detail view for individual activities
    - AuditLogListView: List view for audit logs
    - SecurityEventListView: List view for security events
    - ActivityAPIView: API view for activities
    - UserActivityAPIView: API view for user-specific activities

Author: AdTlas Development Team
Version: 1.0.0
Last Updated: 2024
"""

from django.views.generic import ListView, DetailView
from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.db.models import Q, Count
from django.http import JsonResponse, Http404
from django.core.paginator import Paginator
from django.utils.translation import gettext_lazy as _
from django.urls import reverse_lazy
from django.contrib import messages
from django.shortcuts import get_object_or_404
from django.utils import timezone
from datetime import timedelta

from rest_framework import generics, permissions, filters, status
from rest_framework.decorators import api_view, permission_classes
from rest_framework.response import Response
from rest_framework.pagination import PageNumberPagination
from django_filters.rest_framework import DjangoFilterBackend

from .models import Activity, ActivityType, AuditLog, SecurityEvent
from .serializers import (
    ActivitySerializer, 
    ActivityTypeSerializer,
    AuditLogSerializer,
    SecurityEventSerializer
)
from apps.core.mixins import AdminRequiredMixin, ManagerRequiredMixin
from apps.core.utils import get_client_ip, get_user_agent


class ActivityPagination(PageNumberPagination):
    """
    Custom pagination for activity views.
    """
    page_size = 25
    page_size_query_param = 'page_size'
    max_page_size = 100


class ActivityListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
    """
    List view for displaying activities.
    
    This view shows a paginated list of activities with filtering
    and search capabilities. Access is restricted to users with
    appropriate permissions.
    
    Attributes:
        model: The Activity model
        template_name: Template for rendering the view
        context_object_name: Name for the context object
        paginate_by: Number of items per page
        permission_required: Required permission for access
    """
    
    model = Activity
    template_name = 'activities/activity_list.html'
    context_object_name = 'activities'
    paginate_by = 25
    permission_required = 'activities.view_activity'
    
    def get_queryset(self):
        """
        Get filtered and ordered queryset.
        
        Returns:
            QuerySet: Filtered activities queryset
        """
        queryset = Activity.objects.select_related(
            'user', 'activity_type', 'content_type'
        ).prefetch_related('content_object')
        
        # Apply filters based on query parameters
        user_id = self.request.GET.get('user')
        if user_id:
            queryset = queryset.filter(user_id=user_id)
        
        action = self.request.GET.get('action')
        if action:
            queryset = queryset.filter(action=action)
        
        activity_type = self.request.GET.get('type')
        if activity_type:
            queryset = queryset.filter(activity_type_id=activity_type)
        
        success = self.request.GET.get('success')
        if success is not None:
            queryset = queryset.filter(success=success.lower() == 'true')
        
        # Date range filter
        date_from = self.request.GET.get('date_from')
        date_to = self.request.GET.get('date_to')
        if date_from:
            queryset = queryset.filter(created_at__date__gte=date_from)
        if date_to:
            queryset = queryset.filter(created_at__date__lte=date_to)
        
        # Search functionality
        search = self.request.GET.get('search')
        if search:
            queryset = queryset.filter(
                Q(description__icontains=search) |
                Q(user__email__icontains=search) |
                Q(ip_address__icontains=search)
            )
        
        # Security events filter
        security_only = self.request.GET.get('security_only')
        if security_only:
            queryset = queryset.filter(activity_type__is_security_related=True)
        
        return queryset.order_by('-created_at')
    
    def get_context_data(self, **kwargs):
        """
        Add additional context data.
        
        Args:
            **kwargs: Additional keyword arguments
            
        Returns:
            dict: Context data for the template
        """
        context = super().get_context_data(**kwargs)
        
        # Add filter options
        context['activity_types'] = ActivityType.objects.filter(is_active=True)
        context['action_choices'] = Activity.ACTION_CHOICES
        
        # Add current filters
        context['current_filters'] = {
            'user': self.request.GET.get('user', ''),
            'action': self.request.GET.get('action', ''),
            'type': self.request.GET.get('type', ''),
            'success': self.request.GET.get('success', ''),
            'date_from': self.request.GET.get('date_from', ''),
            'date_to': self.request.GET.get('date_to', ''),
            'search': self.request.GET.get('search', ''),
            'security_only': self.request.GET.get('security_only', ''),
        }
        
        # Add statistics
        total_activities = self.get_queryset().count()
        context['total_activities'] = total_activities
        
        # Recent activity stats
        now = timezone.now()
        today_count = self.get_queryset().filter(
            created_at__date=now.date()
        ).count()
        week_count = self.get_queryset().filter(
            created_at__gte=now - timedelta(days=7)
        ).count()
        
        context['today_count'] = today_count
        context['week_count'] = week_count
        
        return context


class ActivityDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
    """
    Detail view for individual activities.
    
    This view shows detailed information about a specific activity
    including all metadata and related objects.
    
    Attributes:
        model: The Activity model
        template_name: Template for rendering the view
        context_object_name: Name for the context object
        permission_required: Required permission for access
    """
    
    model = Activity
    template_name = 'activities/activity_detail.html'
    context_object_name = 'activity'
    permission_required = 'activities.view_activity'
    
    def get_queryset(self):
        """
        Get queryset with related objects.
        
        Returns:
            QuerySet: Activity queryset with related objects
        """
        return Activity.objects.select_related(
            'user', 'activity_type', 'content_type'
        ).prefetch_related('content_object')
    
    def get_context_data(self, **kwargs):
        """
        Add additional context data.
        
        Args:
            **kwargs: Additional keyword arguments
            
        Returns:
            dict: Context data for the template
        """
        context = super().get_context_data(**kwargs)
        
        # Add related activities
        activity = self.object
        if activity.user:
            context['related_activities'] = Activity.objects.filter(
                user=activity.user
            ).exclude(id=activity.id).order_by('-created_at')[:10]
        
        return context


class UserActivityListView(LoginRequiredMixin, ListView):
    """
    List view for user's own activities.
    
    This view allows users to see their own activity history
    without requiring special permissions.
    
    Attributes:
        model: The Activity model
        template_name: Template for rendering the view
        context_object_name: Name for the context object
        paginate_by: Number of items per page
    """
    
    model = Activity
    template_name = 'activities/user_activity_list.html'
    context_object_name = 'activities'
    paginate_by = 20
    
    def get_queryset(self):
        """
        Get activities for the current user.
        
        Returns:
            QuerySet: User's activities
        """
        return Activity.objects.filter(
            user=self.request.user
        ).select_related('activity_type').order_by('-created_at')
    
    def get_context_data(self, **kwargs):
        """
        Add user-specific context data.
        
        Args:
            **kwargs: Additional keyword arguments
            
        Returns:
            dict: Context data for the template
        """
        context = super().get_context_data(**kwargs)
        
        # Add user activity statistics
        user_activities = self.get_queryset()
        context['total_activities'] = user_activities.count()
        
        # Recent activity counts
        now = timezone.now()
        context['today_count'] = user_activities.filter(
            created_at__date=now.date()
        ).count()
        context['week_count'] = user_activities.filter(
            created_at__gte=now - timedelta(days=7)
        ).count()
        context['month_count'] = user_activities.filter(
            created_at__gte=now - timedelta(days=30)
        ).count()
        
        return context


class AuditLogListView(LoginRequiredMixin, AdminRequiredMixin, ListView):
    """
    List view for audit logs.
    
    This view is restricted to admin users and shows detailed
    audit trails of model changes.
    
    Attributes:
        model: The AuditLog model
        template_name: Template for rendering the view
        context_object_name: Name for the context object
        paginate_by: Number of items per page
    """
    
    model = AuditLog
    template_name = 'activities/audit_log_list.html'
    context_object_name = 'audit_logs'
    paginate_by = 25
    
    def get_queryset(self):
        """
        Get filtered audit logs.
        
        Returns:
            QuerySet: Filtered audit logs
        """
        queryset = AuditLog.objects.select_related('user')
        
        # Apply filters
        model_name = self.request.GET.get('model')
        if model_name:
            queryset = queryset.filter(model_name=model_name)
        
        action = self.request.GET.get('action')
        if action:
            queryset = queryset.filter(action=action)
        
        user_id = self.request.GET.get('user')
        if user_id:
            queryset = queryset.filter(user_id=user_id)
        
        return queryset.order_by('-created_at')
    
    def get_context_data(self, **kwargs):
        """
        Add audit log context data.
        
        Args:
            **kwargs: Additional keyword arguments
            
        Returns:
            dict: Context data for the template
        """
        context = super().get_context_data(**kwargs)
        
        # Add filter options
        context['model_choices'] = AuditLog.objects.values_list(
            'model_name', flat=True
        ).distinct().order_by('model_name')
        context['action_choices'] = AuditLog.ACTION_CHOICES
        
        return context


class SecurityEventListView(LoginRequiredMixin, AdminRequiredMixin, ListView):
    """
    List view for security events.
    
    This view is restricted to admin users and shows security-related
    events that require attention.
    
    Attributes:
        model: The SecurityEvent model
        template_name: Template for rendering the view
        context_object_name: Name for the context object
        paginate_by: Number of items per page
    """
    
    model = SecurityEvent
    template_name = 'activities/security_event_list.html'
    context_object_name = 'security_events'
    paginate_by = 25
    
    def get_queryset(self):
        """
        Get filtered security events.
        
        Returns:
            QuerySet: Filtered security events
        """
        queryset = SecurityEvent.objects.select_related('user', 'resolved_by')
        
        # Apply filters
        event_type = self.request.GET.get('event_type')
        if event_type:
            queryset = queryset.filter(event_type=event_type)
        
        severity = self.request.GET.get('severity')
        if severity:
            queryset = queryset.filter(severity=severity)
        
        resolved = self.request.GET.get('resolved')
        if resolved is not None:
            queryset = queryset.filter(resolved=resolved.lower() == 'true')
        
        return queryset.order_by('-created_at')
    
    def get_context_data(self, **kwargs):
        """
        Add security event context data.
        
        Args:
            **kwargs: Additional keyword arguments
            
        Returns:
            dict: Context data for the template
        """
        context = super().get_context_data(**kwargs)
        
        # Add filter options
        context['event_type_choices'] = SecurityEvent.EVENT_TYPE_CHOICES
        context['severity_choices'] = SecurityEvent.SEVERITY_CHOICES
        
        # Add statistics
        queryset = self.get_queryset()
        context['total_events'] = queryset.count()
        context['unresolved_events'] = queryset.filter(resolved=False).count()
        context['critical_events'] = queryset.filter(
            severity='critical', resolved=False
        ).count()
        
        return context


# API Views
class ActivityAPIView(generics.ListAPIView):
    """
    API view for listing activities.
    
    This view provides a REST API endpoint for retrieving activities
    with filtering, searching, and pagination.
    
    Attributes:
        queryset: Base queryset for activities
        serializer_class: Serializer for activity data
        permission_classes: Required permissions
        filter_backends: Filtering backends
        filterset_fields: Fields available for filtering
        search_fields: Fields available for searching
        ordering_fields: Fields available for ordering
        pagination_class: Pagination class
    """
    
    queryset = Activity.objects.select_related(
        'user', 'activity_type', 'content_type'
    ).all()
    serializer_class = ActivitySerializer
    permission_classes = [permissions.IsAuthenticated]
    filter_backends = [
        DjangoFilterBackend,
        filters.SearchFilter,
        filters.OrderingFilter
    ]
    filterset_fields = [
        'action', 'success', 'activity_type', 'user'
    ]
    search_fields = [
        'description', 'user__email', 'ip_address'
    ]
    ordering_fields = ['created_at', 'action', 'success']
    ordering = ['-created_at']
    pagination_class = ActivityPagination
    
    def get_queryset(self):
        """
        Get filtered queryset based on user permissions.
        
        Returns:
            QuerySet: Filtered activities
        """
        queryset = super().get_queryset()
        
        # If user is not admin/manager, only show their own activities
        if not (self.request.user.is_staff or 
                self.request.user.groups.filter(name__in=['admin', 'manager']).exists()):
            queryset = queryset.filter(user=self.request.user)
        
        return queryset


class UserActivityAPIView(generics.ListAPIView):
    """
    API view for user's own activities.
    
    This view allows users to retrieve their own activity history
    via the API.
    
    Attributes:
        serializer_class: Serializer for activity data
        permission_classes: Required permissions
        pagination_class: Pagination class
    """
    
    serializer_class = ActivitySerializer
    permission_classes = [permissions.IsAuthenticated]
    pagination_class = ActivityPagination
    
    def get_queryset(self):
        """
        Get activities for the current user.
        
        Returns:
            QuerySet: User's activities
        """
        return Activity.objects.filter(
            user=self.request.user
        ).select_related('activity_type').order_by('-created_at')


class ActivityStatsAPIView(generics.GenericAPIView):
    """
    API view for activity statistics.
    
    This view provides statistical data about activities
    for dashboard and reporting purposes.
    
    Attributes:
        permission_classes: Required permissions
    """
    
    permission_classes = [permissions.IsAuthenticated]
    
    def get(self, request, *args, **kwargs):
        """
        Get activity statistics.
        
        Args:
            request: The HTTP request
            *args: Additional arguments
            **kwargs: Additional keyword arguments
            
        Returns:
            Response: Activity statistics data
        """
        # Base queryset
        if request.user.is_staff or request.user.groups.filter(
            name__in=['admin', 'manager']
        ).exists():
            queryset = Activity.objects.all()
        else:
            queryset = Activity.objects.filter(user=request.user)
        
        now = timezone.now()
        
        # Calculate statistics
        stats = {
            'total_activities': queryset.count(),
            'today_activities': queryset.filter(
                created_at__date=now.date()
            ).count(),
            'week_activities': queryset.filter(
                created_at__gte=now - timedelta(days=7)
            ).count(),
            'month_activities': queryset.filter(
                created_at__gte=now - timedelta(days=30)
            ).count(),
            'successful_activities': queryset.filter(success=True).count(),
            'failed_activities': queryset.filter(success=False).count(),
        }
        
        # Activity breakdown by action
        action_stats = queryset.values('action').annotate(
            count=Count('id')
        ).order_by('-count')[:10]
        stats['action_breakdown'] = list(action_stats)
        
        # Recent activity trend (last 7 days)
        trend_data = []
        for i in range(7):
            date = (now - timedelta(days=i)).date()
            count = queryset.filter(created_at__date=date).count()
            trend_data.append({
                'date': date.isoformat(),
                'count': count
            })
        stats['trend_data'] = list(reversed(trend_data))
        
        return Response(stats)


# Utility API Views
@api_view(['POST'])
@permission_classes([permissions.IsAuthenticated])
def log_activity_api(request):
    """
    API endpoint for logging activities.
    
    This endpoint allows applications to log activities
    programmatically via the API.
    
    Args:
        request: The HTTP request with activity data
        
    Returns:
        Response: Success or error response
    """
    try:
        data = request.data
        
        # Extract activity data
        action = data.get('action', 'other')
        description = data.get('description', '')
        activity_type_code = data.get('activity_type', 'general')
        extra_data = data.get('extra_data', {})
        success = data.get('success', True)
        error_message = data.get('error_message', '')
        
        # Get request metadata
        ip_address = get_client_ip(request)
        user_agent = get_user_agent(request)
        session_key = request.session.session_key
        
        # Log the activity
        activity = Activity.log_activity(
            user=request.user,
            action=action,
            description=description,
            ip_address=ip_address,
            user_agent=user_agent,
            session_key=session_key,
            extra_data=extra_data,
            success=success,
            error_message=error_message,
            activity_type_code=activity_type_code
        )
        
        return Response({
            'success': True,
            'activity_id': activity.id,
            'message': 'Activity logged successfully'
        }, status=status.HTTP_201_CREATED)
        
    except Exception as e:
        return Response({
            'success': False,
            'error': str(e)
        }, status=status.HTTP_400_BAD_REQUEST)


@api_view(['GET'])
@permission_classes([permissions.IsAuthenticated])
def activity_export_api(request):
    """
    API endpoint for exporting activities.
    
    This endpoint allows users to export their activity data
    in various formats.
    
    Args:
        request: The HTTP request with export parameters
        
    Returns:
        Response: Exported activity data
    """
    try:
        # Get query parameters
        format_type = request.GET.get('format', 'json')
        date_from = request.GET.get('date_from')
        date_to = request.GET.get('date_to')
        
        # Build queryset
        if request.user.is_staff or request.user.groups.filter(
            name__in=['admin', 'manager']
        ).exists():
            queryset = Activity.objects.all()
        else:
            queryset = Activity.objects.filter(user=request.user)
        
        # Apply date filters
        if date_from:
            queryset = queryset.filter(created_at__date__gte=date_from)
        if date_to:
            queryset = queryset.filter(created_at__date__lte=date_to)
        
        # Limit export size
        queryset = queryset.order_by('-created_at')[:1000]
        
        if format_type == 'json':
            activities = [activity.to_dict() for activity in queryset]
            return Response({
                'activities': activities,
                'count': len(activities)
            })
        
        elif format_type == 'csv':
            import csv
            from django.http import HttpResponse
            
            response = HttpResponse(content_type='text/csv')
            response['Content-Disposition'] = 'attachment; filename="activities.csv"'
            
            writer = csv.writer(response)
            writer.writerow([
                'User', 'Action', 'Description', 'IP Address',
                'Success', 'Created At', 'Activity Type'
            ])
            
            for activity in queryset:
                writer.writerow([
                    activity.user.email if activity.user else 'System',
                    activity.get_action_display(),
                    activity.description,
                    activity.ip_address,
                    'Yes' if activity.success else 'No',
                    activity.created_at.strftime('%Y-%m-%d %H:%M:%S'),
                    activity.activity_type.name
                ])
            
            return response
        
        else:
            return Response({
                'error': 'Unsupported format. Use json or csv.'
            }, status=status.HTTP_400_BAD_REQUEST)
            
    except Exception as e:
        return Response({
            'error': str(e)
        }, status=status.HTTP_400_BAD_REQUEST)