# -*- coding: utf-8 -*-
"""
Adtlas Activities Filters

This module contains Django Filter classes for the activities app,
providing comprehensive filtering capabilities for activity tracking,
analytics, and reporting functionality.

Features:
    - Advanced activity filtering
    - Date range filtering
    - User and category filtering
    - Performance-based filtering
    - Custom filter methods
    - Search functionality

Author: Adtlas Development Team
Version: 1.0.0
Last Updated: 2025-01-27
"""

import django_filters
from django import forms
from django.db.models import Q
from django.utils import timezone
from datetime import datetime, timedelta
from django.contrib.auth import get_user_model
from django.contrib.contenttypes.models import ContentType
from django.utils.translation import gettext_lazy as _

from .models import Activity, ActivityCategory

User = get_user_model()


class ActivityFilter(django_filters.FilterSet):
    """
    Comprehensive filter set for Activity model.
    
    This filter provides advanced filtering capabilities for activities
    including date ranges, user filtering, category filtering, success status,
    performance metrics, and search functionality.
    
    Filters:
        - user: Filter by specific user or multiple users
        - category: Filter by activity category
        - action: Filter by activity action
        - is_successful: Filter by success status
        - date_range: Predefined date range filters
        - date_from/date_to: Custom date range
        - duration_range: Filter by duration ranges
        - ip_address: Filter by IP address
        - content_type: Filter by related object type
        - search: Full-text search across multiple fields
    """
    
    # User filtering
    user = django_filters.ModelMultipleChoiceFilter(
        queryset=User.objects.all(),
        widget=forms.CheckboxSelectMultiple,
        label=_('Users')
    )
    
    user_email = django_filters.CharFilter(
        field_name='user__email',
        lookup_expr='icontains',
        label=_('User Email')
    )
    
    # Category filtering
    category = django_filters.ModelChoiceFilter(
        queryset=ActivityCategory.objects.filter(is_active=True),
        empty_label=_('All Categories'),
        label=_('Category')
    )
    
    category_multiple = django_filters.ModelMultipleChoiceFilter(
        field_name='category',
        queryset=ActivityCategory.objects.filter(is_active=True),
        widget=forms.CheckboxSelectMultiple,
        label=_('Categories')
    )
    
    # Action filtering
    action = django_filters.ChoiceFilter(
        choices=Activity.ACTION_CHOICES,
        empty_label=_('All Actions'),
        label=_('Action')
    )
    
    action_multiple = django_filters.MultipleChoiceFilter(
        field_name='action',
        choices=Activity.ACTION_CHOICES,
        widget=forms.CheckboxSelectMultiple,
        label=_('Actions')
    )
    
    # Success status filtering
    is_successful = django_filters.BooleanFilter(
        widget=forms.Select(choices=[
            ('', _('All')),
            (True, _('Successful')),
            (False, _('Failed'))
        ]),
        label=_('Status')
    )
    
    # Date filtering
    DATE_RANGE_CHOICES = [
        ('today', _('Today')),
        ('yesterday', _('Yesterday')),
        ('last_7_days', _('Last 7 days')),
        ('last_30_days', _('Last 30 days')),
        ('this_week', _('This week')),
        ('this_month', _('This month')),
        ('last_month', _('Last month')),
        ('this_year', _('This year')),
    ]
    
    date_range = django_filters.ChoiceFilter(
        choices=DATE_RANGE_CHOICES,
        method='filter_date_range',
        empty_label=_('All Time'),
        label=_('Date Range')
    )
    
    date_from = django_filters.DateFilter(
        field_name='created_at',
        lookup_expr='date__gte',
        widget=forms.DateInput(attrs={'type': 'date'}),
        label=_('From Date')
    )
    
    date_to = django_filters.DateFilter(
        field_name='created_at',
        lookup_expr='date__lte',
        widget=forms.DateInput(attrs={'type': 'date'}),
        label=_('To Date')
    )
    
    # Time filtering
    time_from = django_filters.TimeFilter(
        field_name='created_at',
        lookup_expr='time__gte',
        widget=forms.TimeInput(attrs={'type': 'time'}),
        label=_('From Time')
    )
    
    time_to = django_filters.TimeFilter(
        field_name='created_at',
        lookup_expr='time__lte',
        widget=forms.TimeInput(attrs={'type': 'time'}),
        label=_('To Time')
    )
    
    # Duration filtering
    DURATION_CHOICES = [
        ('fast', _('Fast (< 1s)')),
        ('normal', _('Normal (1-5s)')),
        ('slow', _('Slow (5-30s)')),
        ('very_slow', _('Very Slow (> 30s)')),
    ]
    
    duration_range = django_filters.ChoiceFilter(
        choices=DURATION_CHOICES,
        method='filter_duration_range',
        empty_label=_('All Durations'),
        label=_('Duration Range')
    )
    
    duration_min = django_filters.NumberFilter(
        field_name='duration_ms',
        lookup_expr='gte',
        label=_('Min Duration (ms)')
    )
    
    duration_max = django_filters.NumberFilter(
        field_name='duration_ms',
        lookup_expr='lte',
        label=_('Max Duration (ms)')
    )
    
    # IP address filtering
    ip_address = django_filters.CharFilter(
        lookup_expr='icontains',
        label=_('IP Address')
    )
    
    # Content type filtering
    content_type = django_filters.ModelChoiceFilter(
        queryset=ContentType.objects.all(),
        empty_label=_('All Object Types'),
        label=_('Object Type')
    )
    
    # Error filtering
    has_error = django_filters.BooleanFilter(
        method='filter_has_error',
        widget=forms.Select(choices=[
            ('', _('All')),
            (True, _('With Errors')),
            (False, _('Without Errors'))
        ]),
        label=_('Has Error')
    )
    
    # Search functionality
    search = django_filters.CharFilter(
        method='filter_search',
        label=_('Search'),
        widget=forms.TextInput(attrs={
            'placeholder': _('Search in description, user, error message...')
        })
    )
    
    # Advanced filters
    has_metadata = django_filters.BooleanFilter(
        method='filter_has_metadata',
        widget=forms.Select(choices=[
            ('', _('All')),
            (True, _('With Metadata')),
            (False, _('Without Metadata'))
        ]),
        label=_('Has Metadata')
    )
    
    session_key = django_filters.CharFilter(
        lookup_expr='icontains',
        label=_('Session Key')
    )
    
    class Meta:
        model = Activity
        fields = {
            'object_id': ['exact'],
            'user_agent': ['icontains'],
        }
    
    def filter_date_range(self, queryset, name, value):
        """
        Filter activities by predefined date ranges.
        
        Args:
            queryset: Base queryset
            name: Filter field name
            value: Selected date range
        
        Returns:
            QuerySet: Filtered queryset
        """
        if not value:
            return queryset
        
        now = timezone.now()
        today = now.date()
        
        if value == 'today':
            return queryset.filter(created_at__date=today)
        
        elif value == 'yesterday':
            yesterday = today - timedelta(days=1)
            return queryset.filter(created_at__date=yesterday)
        
        elif value == 'last_7_days':
            week_ago = today - timedelta(days=7)
            return queryset.filter(created_at__date__gte=week_ago)
        
        elif value == 'last_30_days':
            month_ago = today - timedelta(days=30)
            return queryset.filter(created_at__date__gte=month_ago)
        
        elif value == 'this_week':
            # Get start of current week (Monday)
            days_since_monday = today.weekday()
            week_start = today - timedelta(days=days_since_monday)
            return queryset.filter(created_at__date__gte=week_start)
        
        elif value == 'this_month':
            month_start = today.replace(day=1)
            return queryset.filter(created_at__date__gte=month_start)
        
        elif value == 'last_month':
            # Get first day of last month
            if today.month == 1:
                last_month_start = today.replace(year=today.year-1, month=12, day=1)
                last_month_end = today.replace(day=1) - timedelta(days=1)
            else:
                last_month_start = today.replace(month=today.month-1, day=1)
                last_month_end = today.replace(day=1) - timedelta(days=1)
            
            return queryset.filter(
                created_at__date__gte=last_month_start,
                created_at__date__lte=last_month_end
            )
        
        elif value == 'this_year':
            year_start = today.replace(month=1, day=1)
            return queryset.filter(created_at__date__gte=year_start)
        
        return queryset
    
    def filter_duration_range(self, queryset, name, value):
        """
        Filter activities by duration ranges.
        
        Args:
            queryset: Base queryset
            name: Filter field name
            value: Selected duration range
        
        Returns:
            QuerySet: Filtered queryset
        """
        if not value:
            return queryset
        
        # Exclude activities without duration data
        queryset = queryset.exclude(duration_ms__isnull=True)
        
        if value == 'fast':
            return queryset.filter(duration_ms__lt=1000)
        
        elif value == 'normal':
            return queryset.filter(duration_ms__gte=1000, duration_ms__lt=5000)
        
        elif value == 'slow':
            return queryset.filter(duration_ms__gte=5000, duration_ms__lt=30000)
        
        elif value == 'very_slow':
            return queryset.filter(duration_ms__gte=30000)
        
        return queryset
    
    def filter_has_error(self, queryset, name, value):
        """
        Filter activities by error presence.
        
        Args:
            queryset: Base queryset
            name: Filter field name
            value: Boolean indicating error presence
        
        Returns:
            QuerySet: Filtered queryset
        """
        if value is None:
            return queryset
        
        if value:
            return queryset.exclude(error_message__exact='').exclude(error_message__isnull=True)
        else:
            return queryset.filter(Q(error_message__exact='') | Q(error_message__isnull=True))
    
    def filter_has_metadata(self, queryset, name, value):
        """
        Filter activities by metadata presence.
        
        Args:
            queryset: Base queryset
            name: Filter field name
            value: Boolean indicating metadata presence
        
        Returns:
            QuerySet: Filtered queryset
        """
        if value is None:
            return queryset
        
        if value:
            return queryset.exclude(metadata__isnull=True).exclude(metadata__exact={})
        else:
            return queryset.filter(Q(metadata__isnull=True) | Q(metadata__exact={}))
    
    def filter_search(self, queryset, name, value):
        """
        Perform full-text search across multiple fields.
        
        Args:
            queryset: Base queryset
            name: Filter field name
            value: Search query
        
        Returns:
            QuerySet: Filtered queryset
        """
        if not value:
            return queryset
        
        # Split search terms for better matching
        search_terms = value.split()
        
        # Build search query
        search_query = Q()
        
        for term in search_terms:
            term_query = (
                Q(description__icontains=term) |
                Q(user__email__icontains=term) |
                Q(user__first_name__icontains=term) |
                Q(user__last_name__icontains=term) |
                Q(error_message__icontains=term) |
                Q(category__name__icontains=term) |
                Q(ip_address__icontains=term) |
                Q(user_agent__icontains=term)
            )
            
            # Add to main search query
            if search_query:
                search_query &= term_query
            else:
                search_query = term_query
        
        return queryset.filter(search_query)


class ActivityCategoryFilter(django_filters.FilterSet):
    """
    Filter set for ActivityCategory model.
    
    This filter provides filtering capabilities for activity categories
    including name search, status filtering, and ordering options.
    
    Filters:
        - name: Filter by category name
        - code: Filter by category code
        - is_active: Filter by active status
        - search: Full-text search across name and description
    """
    
    name = django_filters.CharFilter(
        lookup_expr='icontains',
        label=_('Name')
    )
    
    code = django_filters.CharFilter(
        lookup_expr='icontains',
        label=_('Code')
    )
    
    is_active = django_filters.BooleanFilter(
        widget=forms.Select(choices=[
            ('', _('All')),
            (True, _('Active')),
            (False, _('Inactive'))
        ]),
        label=_('Status')
    )
    
    search = django_filters.CharFilter(
        method='filter_search',
        label=_('Search'),
        widget=forms.TextInput(attrs={
            'placeholder': _('Search in name, code, description...')
        })
    )
    
    class Meta:
        model = ActivityCategory
        fields = ['name', 'code', 'is_active']
    
    def filter_search(self, queryset, name, value):
        """
        Perform full-text search across category fields.
        
        Args:
            queryset: Base queryset
            name: Filter field name
            value: Search query
        
        Returns:
            QuerySet: Filtered queryset
        """
        if not value:
            return queryset
        
        return queryset.filter(
            Q(name__icontains=value) |
            Q(code__icontains=value) |
            Q(description__icontains=value)
        )


class UserActivityFilter(django_filters.FilterSet):
    """
    Specialized filter for user-specific activity views.
    
    This filter provides filtering capabilities specifically designed
    for user activity dashboards and personal activity tracking.
    
    Filters:
        - category: Filter by activity category
        - action: Filter by activity action
        - is_successful: Filter by success status
        - date_range: Predefined date range filters
        - search: Search in activity descriptions
    """
    
    category = django_filters.ModelChoiceFilter(
        queryset=ActivityCategory.objects.filter(is_active=True),
        empty_label=_('All Categories'),
        label=_('Category')
    )
    
    action = django_filters.ChoiceFilter(
        choices=Activity.ACTION_CHOICES,
        empty_label=_('All Actions'),
        label=_('Action')
    )
    
    is_successful = django_filters.BooleanFilter(
        widget=forms.Select(choices=[
            ('', _('All')),
            (True, _('Successful')),
            (False, _('Failed'))
        ]),
        label=_('Status')
    )
    
    date_range = django_filters.ChoiceFilter(
        choices=ActivityFilter.DATE_RANGE_CHOICES,
        method='filter_date_range',
        empty_label=_('All Time'),
        label=_('Date Range')
    )
    
    search = django_filters.CharFilter(
        field_name='description',
        lookup_expr='icontains',
        label=_('Search'),
        widget=forms.TextInput(attrs={
            'placeholder': _('Search in descriptions...')
        })
    )
    
    class Meta:
        model = Activity
        fields = ['category', 'action', 'is_successful']
    
    def filter_date_range(self, queryset, name, value):
        """
        Filter activities by predefined date ranges.
        
        Args:
            queryset: Base queryset
            name: Filter field name
            value: Selected date range
        
        Returns:
            QuerySet: Filtered queryset
        """
        # Reuse the date range filtering logic from ActivityFilter
        activity_filter = ActivityFilter()
        return activity_filter.filter_date_range(queryset, name, value)


class ActivityAnalyticsFilter(django_filters.FilterSet):
    """
    Specialized filter for activity analytics and reporting.
    
    This filter provides advanced filtering capabilities specifically
    designed for analytics dashboards and reporting functionality.
    
    Filters:
        - date_from/date_to: Custom date range for analytics
        - category_multiple: Multiple category selection
        - user_multiple: Multiple user selection
        - action_multiple: Multiple action selection
        - performance_filter: Filter by performance metrics
    """
    
    date_from = django_filters.DateFilter(
        field_name='created_at',
        lookup_expr='date__gte',
        widget=forms.DateInput(attrs={'type': 'date'}),
        label=_('From Date')
    )
    
    date_to = django_filters.DateFilter(
        field_name='created_at',
        lookup_expr='date__lte',
        widget=forms.DateInput(attrs={'type': 'date'}),
        label=_('To Date')
    )
    
    category_multiple = django_filters.ModelMultipleChoiceFilter(
        field_name='category',
        queryset=ActivityCategory.objects.filter(is_active=True),
        widget=forms.CheckboxSelectMultiple,
        label=_('Categories')
    )
    
    user_multiple = django_filters.ModelMultipleChoiceFilter(
        field_name='user',
        queryset=User.objects.filter(is_active=True),
        widget=forms.CheckboxSelectMultiple,
        label=_('Users')
    )
    
    action_multiple = django_filters.MultipleChoiceFilter(
        field_name='action',
        choices=Activity.ACTION_CHOICES,
        widget=forms.CheckboxSelectMultiple,
        label=_('Actions')
    )
    
    PERFORMANCE_CHOICES = [
        ('high_performance', _('High Performance (< 1s)')),
        ('medium_performance', _('Medium Performance (1-5s)')),
        ('low_performance', _('Low Performance (> 5s)')),
        ('with_errors', _('With Errors')),
        ('without_errors', _('Without Errors')),
    ]
    
    performance_filter = django_filters.ChoiceFilter(
        choices=PERFORMANCE_CHOICES,
        method='filter_performance',
        empty_label=_('All Performance'),
        label=_('Performance Filter')
    )
    
    class Meta:
        model = Activity
        fields = []
    
    def filter_performance(self, queryset, name, value):
        """
        Filter activities by performance criteria.
        
        Args:
            queryset: Base queryset
            name: Filter field name
            value: Selected performance filter
        
        Returns:
            QuerySet: Filtered queryset
        """
        if not value:
            return queryset
        
        if value == 'high_performance':
            return queryset.filter(duration_ms__lt=1000)
        
        elif value == 'medium_performance':
            return queryset.filter(duration_ms__gte=1000, duration_ms__lte=5000)
        
        elif value == 'low_performance':
            return queryset.filter(duration_ms__gt=5000)
        
        elif value == 'with_errors':
            return queryset.exclude(error_message__exact='').exclude(error_message__isnull=True)
        
        elif value == 'without_errors':
            return queryset.filter(Q(error_message__exact='') | Q(error_message__isnull=True))
        
        return queryset