"""Filters for Reporting and Analytics app."""

import django_filters
from django.db.models import Q
from django.utils import timezone
from datetime import datetime, timedelta

from .models import (
    AnalyticsRegion,
    AnalyticsTarget,
    SfrAnalytics,
    MarketShare,
    VerificationRecord,
    PredictionModel,
    SfrPrediction,
    AdbreakPrediction,
    ActivityLog,
    RealTimeAdbreak,
)
from apps.channels.models import Channel
from apps.campaigns.models import Campaign
from apps.advertisers.models import Brand


class SfrAnalyticsFilter(django_filters.FilterSet):
    """Filter for SFR Analytics data."""
    
    # Date filters
    measurement_date = django_filters.DateFilter()
    measurement_date_from = django_filters.DateFilter(
        field_name='measurement_date',
        lookup_expr='gte',
        label='Measurement date from'
    )
    measurement_date_to = django_filters.DateFilter(
        field_name='measurement_date',
        lookup_expr='lte',
        label='Measurement date to'
    )
    measurement_date_range = django_filters.DateFromToRangeFilter(
        field_name='measurement_date',
        label='Measurement date range'
    )
    
    # Time filters
    measurement_time_from = django_filters.TimeFilter(
        field_name='measurement_time',
        lookup_expr='gte',
        label='Measurement time from'
    )
    measurement_time_to = django_filters.TimeFilter(
        field_name='measurement_time',
        lookup_expr='lte',
        label='Measurement time to'
    )
    
    # Channel filters
    channel = django_filters.ModelChoiceFilter(
        queryset=Channel.objects.all(),
        label='Channel'
    )
    channel_name = django_filters.CharFilter(
        field_name='channel__name',
        lookup_expr='icontains',
        label='Channel name contains'
    )
    sfr_channel_name = django_filters.CharFilter(
        lookup_expr='icontains',
        label='SFR channel name contains'
    )
    
    # Region and target filters
    region = django_filters.ModelChoiceFilter(
        queryset=AnalyticsRegion.objects.all(),
        label='Region'
    )
    region_name = django_filters.CharFilter(
        field_name='region__name',
        lookup_expr='icontains',
        label='Region name contains'
    )
    target = django_filters.ModelChoiceFilter(
        queryset=AnalyticsTarget.objects.all(),
        label='Target'
    )
    target_name = django_filters.CharFilter(
        field_name='target__name',
        lookup_expr='icontains',
        label='Target name contains'
    )
    
    # Indicator filters
    indicator = django_filters.ChoiceFilter(
        choices=SfrAnalytics.INDICATOR_CHOICES,
        label='Indicator'
    )
    
    # Value filters
    value_min = django_filters.NumberFilter(
        field_name='value',
        lookup_expr='gte',
        label='Minimum value'
    )
    value_max = django_filters.NumberFilter(
        field_name='value',
        lookup_expr='lte',
        label='Maximum value'
    )
    value_range = django_filters.RangeFilter(
        field_name='value',
        label='Value range'
    )
    
    # Percentage filters
    percentage_min = django_filters.NumberFilter(
        field_name='percentage',
        lookup_expr='gte',
        label='Minimum percentage'
    )
    percentage_max = django_filters.NumberFilter(
        field_name='percentage',
        lookup_expr='lte',
        label='Maximum percentage'
    )
    
    # Quality filters
    quality_score_min = django_filters.NumberFilter(
        field_name='quality_score',
        lookup_expr='gte',
        label='Minimum quality score'
    )
    quality_score_max = django_filters.NumberFilter(
        field_name='quality_score',
        lookup_expr='lte',
        label='Maximum quality score'
    )
    
    # Data source filter
    data_source = django_filters.CharFilter(
        lookup_expr='icontains',
        label='Data source contains'
    )
    
    # Recent data filter
    recent_days = django_filters.NumberFilter(
        method='filter_recent_days',
        label='Recent days'
    )
    
    class Meta:
        model = SfrAnalytics
        fields = [
            'measurement_date', 'channel', 'region', 'target',
            'indicator', 'data_source'
        ]
    
    def filter_recent_days(self, queryset, name, value):
        """Filter analytics from recent days."""
        if value:
            cutoff_date = timezone.now().date() - timedelta(days=value)
            return queryset.filter(measurement_date__gte=cutoff_date)
        return queryset


class MarketShareFilter(django_filters.FilterSet):
    """Filter for Market Share data."""
    
    # Date filters
    measurement_date = django_filters.DateFilter()
    measurement_date_from = django_filters.DateFilter(
        field_name='measurement_date',
        lookup_expr='gte',
        label='Measurement date from'
    )
    measurement_date_to = django_filters.DateFilter(
        field_name='measurement_date',
        lookup_expr='lte',
        label='Measurement date to'
    )
    measurement_date_range = django_filters.DateFromToRangeFilter(
        field_name='measurement_date',
        label='Measurement date range'
    )
    
    # Channel filters
    channel = django_filters.ModelChoiceFilter(
        queryset=Channel.objects.all(),
        label='Channel'
    )
    channel_name = django_filters.CharFilter(
        field_name='channel__name',
        lookup_expr='icontains',
        label='Channel name contains'
    )
    
    # Region and target filters
    region = django_filters.ModelChoiceFilter(
        queryset=AnalyticsRegion.objects.all(),
        label='Region'
    )
    target = django_filters.ModelChoiceFilter(
        queryset=AnalyticsTarget.objects.all(),
        label='Target'
    )
    
    # Market share filters
    market_share_min = django_filters.NumberFilter(
        field_name='market_share_percentage',
        lookup_expr='gte',
        label='Minimum market share %'
    )
    market_share_max = django_filters.NumberFilter(
        field_name='market_share_percentage',
        lookup_expr='lte',
        label='Maximum market share %'
    )
    
    # Ranking filters
    ranking_min = django_filters.NumberFilter(
        field_name='ranking',
        lookup_expr='gte',
        label='Minimum ranking'
    )
    ranking_max = django_filters.NumberFilter(
        field_name='ranking',
        lookup_expr='lte',
        label='Maximum ranking'
    )
    top_rankings = django_filters.NumberFilter(
        method='filter_top_rankings',
        label='Top N rankings'
    )
    
    # User count filters
    total_users_min = django_filters.NumberFilter(
        field_name='total_users',
        lookup_expr='gte',
        label='Minimum total users'
    )
    channel_users_min = django_filters.NumberFilter(
        field_name='channel_users',
        lookup_expr='gte',
        label='Minimum channel users'
    )
    
    # Tool filter
    tool_name = django_filters.CharFilter(
        lookup_expr='icontains',
        label='Tool name contains'
    )
    
    class Meta:
        model = MarketShare
        fields = [
            'measurement_date', 'channel', 'region', 'target', 'tool_name'
        ]
    
    def filter_top_rankings(self, queryset, name, value):
        """Filter top N rankings."""
        if value:
            return queryset.filter(ranking__lte=value)
        return queryset


class VerificationRecordFilter(django_filters.FilterSet):
    """Filter for Verification Records."""
    
    # Date filters
    broadcast_date = django_filters.DateFilter()
    broadcast_date_from = django_filters.DateFilter(
        field_name='broadcast_date',
        lookup_expr='gte',
        label='Broadcast date from'
    )
    broadcast_date_to = django_filters.DateFilter(
        field_name='broadcast_date',
        lookup_expr='lte',
        label='Broadcast date to'
    )
    broadcast_date_range = django_filters.DateFromToRangeFilter(
        field_name='broadcast_date',
        label='Broadcast date range'
    )
    
    # Time filters
    broadcast_time_from = django_filters.TimeFilter(
        field_name='broadcast_time',
        lookup_expr='gte',
        label='Broadcast time from'
    )
    broadcast_time_to = django_filters.TimeFilter(
        field_name='broadcast_time',
        lookup_expr='lte',
        label='Broadcast time to'
    )
    
    # Network and zone filters
    network_name = django_filters.CharFilter(
        lookup_expr='icontains',
        label='Network name contains'
    )
    zone_name = django_filters.CharFilter(
        lookup_expr='icontains',
        label='Zone name contains'
    )
    
    # Status filters
    status = django_filters.ChoiceFilter(
        choices=VerificationRecord.STATUS_CHOICES,
        label='Status'
    )
    pending_only = django_filters.BooleanFilter(
        method='filter_pending_only',
        label='Pending only'
    )
    verified_only = django_filters.BooleanFilter(
        method='filter_verified_only',
        label='Verified only'
    )
    failed_only = django_filters.BooleanFilter(
        method='filter_failed_only',
        label='Failed only'
    )
    
    # ID filters
    traffic_id = django_filters.NumberFilter()
    spot_id = django_filters.CharFilter(
        lookup_expr='icontains',
        label='Spot ID contains'
    )
    
    # Campaign and advertiser filters
    campaign = django_filters.ModelChoiceFilter(
        queryset=Campaign.objects.all(),
        label='Campaign'
    )
    campaign_name = django_filters.CharFilter(
        field_name='campaign__name',
        lookup_expr='icontains',
        label='Campaign name contains'
    )
    advertiser = django_filters.ModelChoiceFilter(
        queryset=Brand.objects.all(),
        label='Advertiser'
    )
    advertiser_name = django_filters.CharFilter(
        field_name='advertiser__name',
        lookup_expr='icontains',
        label='Advertiser name contains'
    )
    
    # Verification filters
    verified_by = django_filters.CharFilter(
        field_name='verified_by__username',
        lookup_expr='icontains',
        label='Verified by username contains'
    )
    verification_complete = django_filters.CharFilter(
        lookup_expr='icontains',
        label='Verification complete contains'
    )
    
    # Recent filters
    recent_days = django_filters.NumberFilter(
        method='filter_recent_days',
        label='Recent days'
    )
    
    class Meta:
        model = VerificationRecord
        fields = [
            'broadcast_date', 'status', 'network_name', 'zone_name',
            'traffic_id', 'spot_id', 'campaign', 'advertiser'
        ]
    
    def filter_pending_only(self, queryset, name, value):
        """Filter pending verifications only."""
        if value:
            return queryset.filter(status='pending')
        return queryset
    
    def filter_verified_only(self, queryset, name, value):
        """Filter verified records only."""
        if value:
            return queryset.filter(status='verified')
        return queryset
    
    def filter_failed_only(self, queryset, name, value):
        """Filter failed verifications only."""
        if value:
            return queryset.filter(status='failed')
        return queryset
    
    def filter_recent_days(self, queryset, name, value):
        """Filter verifications from recent days."""
        if value:
            cutoff_date = timezone.now().date() - timedelta(days=value)
            return queryset.filter(broadcast_date__gte=cutoff_date)
        return queryset


class SfrPredictionFilter(django_filters.FilterSet):
    """Filter for SFR Predictions."""
    
    # Date filters
    prediction_date = django_filters.DateFilter()
    prediction_date_from = django_filters.DateFilter(
        field_name='prediction_date',
        lookup_expr='gte',
        label='Prediction date from'
    )
    prediction_date_to = django_filters.DateFilter(
        field_name='prediction_date',
        lookup_expr='lte',
        label='Prediction date to'
    )
    prediction_date_range = django_filters.DateFromToRangeFilter(
        field_name='prediction_date',
        label='Prediction date range'
    )
    
    # Model filters
    model = django_filters.ModelChoiceFilter(
        queryset=PredictionModel.objects.all(),
        label='Prediction model'
    )
    model_name = django_filters.CharFilter(
        field_name='model__name',
        lookup_expr='icontains',
        label='Model name contains'
    )
    model_type = django_filters.ChoiceFilter(
        field_name='model__model_type',
        choices=PredictionModel.MODEL_TYPES,
        label='Model type'
    )
    
    # Channel filters
    channel = django_filters.ModelChoiceFilter(
        queryset=Channel.objects.all(),
        label='Channel'
    )
    channel_name = django_filters.CharFilter(
        field_name='channel__name',
        lookup_expr='icontains',
        label='Channel name contains'
    )
    
    # Region and target filters
    region = django_filters.ModelChoiceFilter(
        queryset=AnalyticsRegion.objects.all(),
        label='Region'
    )
    target = django_filters.ModelChoiceFilter(
        queryset=AnalyticsTarget.objects.all(),
        label='Target'
    )
    
    # Indicator filter
    indicator = django_filters.ChoiceFilter(
        choices=SfrAnalytics.INDICATOR_CHOICES,
        label='Indicator'
    )
    
    # Value filters
    predicted_value_min = django_filters.NumberFilter(
        field_name='predicted_value',
        lookup_expr='gte',
        label='Minimum predicted value'
    )
    predicted_value_max = django_filters.NumberFilter(
        field_name='predicted_value',
        lookup_expr='lte',
        label='Maximum predicted value'
    )
    
    # Confidence filters
    confidence_min = django_filters.NumberFilter(
        field_name='confidence_score',
        lookup_expr='gte',
        label='Minimum confidence score'
    )
    confidence_max = django_filters.NumberFilter(
        field_name='confidence_score',
        lookup_expr='lte',
        label='Maximum confidence score'
    )
    
    # Accuracy filters
    has_actual_value = django_filters.BooleanFilter(
        method='filter_has_actual_value',
        label='Has actual value'
    )
    high_accuracy = django_filters.BooleanFilter(
        method='filter_high_accuracy',
        label='High accuracy (>90%)'
    )
    
    class Meta:
        model = SfrPrediction
        fields = [
            'prediction_date', 'model', 'channel', 'region',
            'target', 'indicator'
        ]
    
    def filter_has_actual_value(self, queryset, name, value):
        """Filter predictions with actual values."""
        if value:
            return queryset.filter(actual_value__isnull=False)
        elif value is False:
            return queryset.filter(actual_value__isnull=True)
        return queryset
    
    def filter_high_accuracy(self, queryset, name, value):
        """Filter high accuracy predictions."""
        if value:
            # This would need to be implemented with a custom query
            # since accuracy is a property, not a field
            return queryset.filter(actual_value__isnull=False)
        return queryset


class AdbreakPredictionFilter(django_filters.FilterSet):
    """Filter for Ad Break Predictions."""
    
    # Date filters
    prediction_date = django_filters.DateFilter()
    prediction_date_from = django_filters.DateFilter(
        field_name='prediction_date',
        lookup_expr='gte',
        label='Prediction date from'
    )
    prediction_date_to = django_filters.DateFilter(
        field_name='prediction_date',
        lookup_expr='lte',
        label='Prediction date to'
    )
    
    # DateTime filters
    prediction_datetime_from = django_filters.DateTimeFilter(
        field_name='prediction_datetime',
        lookup_expr='gte',
        label='Prediction datetime from'
    )
    prediction_datetime_to = django_filters.DateTimeFilter(
        field_name='prediction_datetime',
        lookup_expr='lte',
        label='Prediction datetime to'
    )
    
    # Model filters
    model = django_filters.ModelChoiceFilter(
        queryset=PredictionModel.objects.all(),
        label='Prediction model'
    )
    model_name = django_filters.CharFilter(
        field_name='model__name',
        lookup_expr='icontains',
        label='Model name contains'
    )
    
    # Channel filters
    channel = django_filters.ModelChoiceFilter(
        queryset=Channel.objects.all(),
        label='Channel'
    )
    channel_name = django_filters.CharFilter(
        field_name='channel__name',
        lookup_expr='icontains',
        label='Channel name contains'
    )
    
    # Duration filters
    predicted_duration_min = django_filters.NumberFilter(
        field_name='predicted_duration_seconds',
        lookup_expr='gte',
        label='Minimum predicted duration (seconds)'
    )
    predicted_duration_max = django_filters.NumberFilter(
        field_name='predicted_duration_seconds',
        lookup_expr='lte',
        label='Maximum predicted duration (seconds)'
    )
    
    # Confidence filters
    confidence_min = django_filters.NumberFilter(
        field_name='confidence_score',
        lookup_expr='gte',
        label='Minimum confidence score'
    )
    confidence_max = django_filters.NumberFilter(
        field_name='confidence_score',
        lookup_expr='lte',
        label='Maximum confidence score'
    )
    
    # Actual data filters
    has_actual_data = django_filters.BooleanFilter(
        method='filter_has_actual_data',
        label='Has actual data'
    )
    
    class Meta:
        model = AdbreakPrediction
        fields = [
            'prediction_date', 'model', 'channel'
        ]
    
    def filter_has_actual_data(self, queryset, name, value):
        """Filter predictions with actual data."""
        if value:
            return queryset.filter(actual_datetime__isnull=False)
        elif value is False:
            return queryset.filter(actual_datetime__isnull=True)
        return queryset


class ActivityLogFilter(django_filters.FilterSet):
    """Filter for Activity Logs."""
    
    # Date filters
    activity_date = django_filters.DateFilter()
    activity_date_from = django_filters.DateFilter(
        field_name='activity_date',
        lookup_expr='gte',
        label='Activity date from'
    )
    activity_date_to = django_filters.DateFilter(
        field_name='activity_date',
        lookup_expr='lte',
        label='Activity date to'
    )
    activity_date_range = django_filters.DateFromToRangeFilter(
        field_name='activity_date',
        label='Activity date range'
    )
    
    # Created date filters
    created_from = django_filters.DateTimeFilter(
        field_name='created_at',
        lookup_expr='gte',
        label='Created from'
    )
    created_to = django_filters.DateTimeFilter(
        field_name='created_at',
        lookup_expr='lte',
        label='Created to'
    )
    
    # Activity type filters
    activity_type = django_filters.ChoiceFilter(
        choices=ActivityLog.ACTIVITY_TYPES,
        label='Activity type'
    )
    activity_types = django_filters.MultipleChoiceFilter(
        field_name='activity_type',
        choices=ActivityLog.ACTIVITY_TYPES,
        label='Activity types'
    )
    
    # User filters
    user = django_filters.CharFilter(
        field_name='user__username',
        lookup_expr='icontains',
        label='Username contains'
    )
    user_id = django_filters.NumberFilter(
        field_name='user__id',
        label='User ID'
    )
    
    # Description filter
    description = django_filters.CharFilter(
        lookup_expr='icontains',
        label='Description contains'
    )
    
    # IP address filter
    ip_address = django_filters.CharFilter(
        lookup_expr='icontains',
        label='IP address contains'
    )
    
    # Recent filters
    recent_hours = django_filters.NumberFilter(
        method='filter_recent_hours',
        label='Recent hours'
    )
    recent_days = django_filters.NumberFilter(
        method='filter_recent_days',
        label='Recent days'
    )
    
    class Meta:
        model = ActivityLog
        fields = [
            'activity_date', 'activity_type', 'user'
        ]
    
    def filter_recent_hours(self, queryset, name, value):
        """Filter activities from recent hours."""
        if value:
            cutoff_time = timezone.now() - timedelta(hours=value)
            return queryset.filter(created_at__gte=cutoff_time)
        return queryset
    
    def filter_recent_days(self, queryset, name, value):
        """Filter activities from recent days."""
        if value:
            cutoff_date = timezone.now().date() - timedelta(days=value)
            return queryset.filter(activity_date__gte=cutoff_date)
        return queryset


class RealTimeAdbreakFilter(django_filters.FilterSet):
    """Filter for Real-time Ad Breaks."""
    
    # Date filters
    start_date = django_filters.DateFilter(
        field_name='start_time__date',
        label='Start date'
    )
    start_date_from = django_filters.DateFilter(
        field_name='start_time__date',
        lookup_expr='gte',
        label='Start date from'
    )
    start_date_to = django_filters.DateFilter(
        field_name='start_time__date',
        lookup_expr='lte',
        label='Start date to'
    )
    
    # DateTime filters
    start_time_from = django_filters.DateTimeFilter(
        field_name='start_time',
        lookup_expr='gte',
        label='Start time from'
    )
    start_time_to = django_filters.DateTimeFilter(
        field_name='start_time',
        lookup_expr='lte',
        label='Start time to'
    )
    
    # Channel filters
    channel = django_filters.ModelChoiceFilter(
        queryset=Channel.objects.all(),
        label='Channel'
    )
    channel_name = django_filters.CharFilter(
        field_name='channel__name',
        lookup_expr='icontains',
        label='Channel name contains'
    )
    
    # Status filters
    status = django_filters.ChoiceFilter(
        choices=RealTimeAdbreak.STATUS_CHOICES,
        label='Status'
    )
    active_only = django_filters.BooleanFilter(
        method='filter_active_only',
        label='Active only'
    )
    completed_only = django_filters.BooleanFilter(
        method='filter_completed_only',
        label='Completed only'
    )
    
    # Duration filters
    duration_min = django_filters.NumberFilter(
        field_name='duration_seconds',
        lookup_expr='gte',
        label='Minimum duration (seconds)'
    )
    duration_max = django_filters.NumberFilter(
        field_name='duration_seconds',
        lookup_expr='lte',
        label='Maximum duration (seconds)'
    )
    
    # Performance filters
    ad_count_min = django_filters.NumberFilter(
        field_name='ad_count',
        lookup_expr='gte',
        label='Minimum ad count'
    )
    viewer_count_min = django_filters.NumberFilter(
        field_name='viewer_count',
        lookup_expr='gte',
        label='Minimum viewer count'
    )
    revenue_min = django_filters.NumberFilter(
        field_name='total_revenue',
        lookup_expr='gte',
        label='Minimum revenue'
    )
    
    # Recent filters
    recent_hours = django_filters.NumberFilter(
        method='filter_recent_hours',
        label='Recent hours'
    )
    
    class Meta:
        model = RealTimeAdbreak
        fields = [
            'start_time', 'channel', 'status'
        ]
    
    def filter_active_only(self, queryset, name, value):
        """Filter active ad breaks only."""
        if value:
            return queryset.filter(
                status__in=['scheduled', 'started', 'in_progress']
            )
        return queryset
    
    def filter_completed_only(self, queryset, name, value):
        """Filter completed ad breaks only."""
        if value:
            return queryset.filter(status='completed')
        return queryset
    
    def filter_recent_hours(self, queryset, name, value):
        """Filter ad breaks from recent hours."""
        if value:
            cutoff_time = timezone.now() - timedelta(hours=value)
            return queryset.filter(start_time__gte=cutoff_time)
        return queryset