"""Filters for adspots app.

This module provides Django Filter classes for:
- Adspot: Filtering advertising spots
- Avail: Filtering availability windows
- Window: Filtering time windows
- AdspotInAvail: Filtering adspot placements
- Pending: Filtering pending creatives
"""

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

from .models import Adspot, Avail, Window, AdspotInAvail, Pending
from apps.campaigns.models import Campaign
from apps.advertisers.models import Brand
from apps.channels.models import Channel


class AdspotFilter(django_filters.FilterSet):
    """Filter for Adspot model."""
    
    # Text search filters
    name = django_filters.CharFilter(
        field_name='name',
        lookup_expr='icontains',
        label='Name contains'
    )
    
    creative_id = django_filters.CharFilter(
        field_name='creative_id',
        lookup_expr='icontains',
        label='Creative ID contains'
    )
    
    filename = django_filters.CharFilter(
        field_name='filename',
        lookup_expr='icontains',
        label='Filename contains'
    )
    
    # Relationship filters
    campaign = django_filters.ModelChoiceFilter(
        field_name='campaign',
        queryset=Campaign.objects.all(),
        label='Campaign'
    )
    
    brand = django_filters.ModelChoiceFilter(
        field_name='brand',
        queryset=Brand.objects.all(),
        label='Brand'
    )
    
    channel = django_filters.ModelChoiceFilter(
        field_name='channel',
        queryset=Channel.objects.all(),
        label='Channel'
    )
    
    # Status filters
    processing_status = django_filters.ChoiceFilter(
        field_name='processing_status',
        choices=Adspot.PROCESSING_STATUS_CHOICES,
        label='Processing Status'
    )
    
    is_processed = django_filters.BooleanFilter(
        field_name='is_processed',
        label='Is Processed'
    )
    
    status = django_filters.ChoiceFilter(
        field_name='status',
        choices=Adspot.STATUS_CHOICES,
        label='Status'
    )
    
    # Format filters
    format = django_filters.ChoiceFilter(
        field_name='format',
        choices=Adspot.FORMAT_CHOICES,
        label='Format'
    )
    
    # File size filters
    file_size_min = django_filters.NumberFilter(
        field_name='file_size',
        lookup_expr='gte',
        label='Minimum file size (bytes)'
    )
    
    file_size_max = django_filters.NumberFilter(
        field_name='file_size',
        lookup_expr='lte',
        label='Maximum file size (bytes)'
    )
    
    # Duration filters
    duration = django_filters.CharFilter(
        field_name='duration',
        lookup_expr='icontains',
        label='Duration contains'
    )
    
    # Resolution filters
    resolution = django_filters.CharFilter(
        field_name='resolution',
        lookup_expr='icontains',
        label='Resolution contains'
    )
    
    # Bitrate filters
    bitrate_min = django_filters.NumberFilter(
        field_name='bitrate',
        lookup_expr='gte',
        label='Minimum bitrate'
    )
    
    bitrate_max = django_filters.NumberFilter(
        field_name='bitrate',
        lookup_expr='lte',
        label='Maximum bitrate'
    )
    
    # Date filters
    created_after = django_filters.DateTimeFilter(
        field_name='created_at',
        lookup_expr='gte',
        label='Created after'
    )
    
    created_before = django_filters.DateTimeFilter(
        field_name='created_at',
        lookup_expr='lte',
        label='Created before'
    )
    
    created_date = django_filters.DateFilter(
        field_name='created_at',
        lookup_expr='date',
        label='Created on date'
    )
    
    # Date range filters
    created_date_range = django_filters.DateFromToRangeFilter(
        field_name='created_at',
        label='Created date range'
    )
    
    updated_after = django_filters.DateTimeFilter(
        field_name='updated_at',
        lookup_expr='gte',
        label='Updated after'
    )
    
    updated_before = django_filters.DateTimeFilter(
        field_name='updated_at',
        lookup_expr='lte',
        label='Updated before'
    )
    
    # Custom filters
    has_vast_url = django_filters.BooleanFilter(
        method='filter_has_vast_url',
        label='Has VAST URL'
    )
    
    has_encoded_file = django_filters.BooleanFilter(
        method='filter_has_encoded_file',
        label='Has encoded file'
    )
    
    has_error = django_filters.BooleanFilter(
        method='filter_has_error',
        label='Has processing error'
    )
    
    # Time-based filters
    created_today = django_filters.BooleanFilter(
        method='filter_created_today',
        label='Created today'
    )
    
    created_this_week = django_filters.BooleanFilter(
        method='filter_created_this_week',
        label='Created this week'
    )
    
    created_this_month = django_filters.BooleanFilter(
        method='filter_created_this_month',
        label='Created this month'
    )
    
    class Meta:
        model = Adspot
        fields = {
            'name': ['exact', 'icontains'],
            'creative_id': ['exact', 'icontains'],
            'filename': ['exact', 'icontains'],
            'campaign': ['exact'],
            'brand': ['exact'],
            'channel': ['exact'],
            'processing_status': ['exact'],
            'is_processed': ['exact'],
            'status': ['exact'],
            'format': ['exact'],
            'file_size': ['exact', 'gte', 'lte'],
            'duration': ['exact', 'icontains'],
            'resolution': ['exact', 'icontains'],
            'bitrate': ['exact', 'gte', 'lte'],
            'created_at': ['exact', 'gte', 'lte', 'date'],
            'updated_at': ['exact', 'gte', 'lte', 'date'],
        }
    
    def filter_has_vast_url(self, queryset, name, value):
        """Filter by presence of VAST URL."""
        if value is True:
            return queryset.exclude(vast_url__isnull=True).exclude(vast_url='')
        elif value is False:
            return queryset.filter(models.Q(vast_url__isnull=True) | models.Q(vast_url=''))
        return queryset
    
    def filter_has_encoded_file(self, queryset, name, value):
        """Filter by presence of encoded file."""
        if value is True:
            return queryset.exclude(encoded_file__isnull=True).exclude(encoded_file='')
        elif value is False:
            return queryset.filter(models.Q(encoded_file__isnull=True) | models.Q(encoded_file=''))
        return queryset
    
    def filter_has_error(self, queryset, name, value):
        """Filter by presence of error message."""
        if value is True:
            return queryset.exclude(error_message__isnull=True).exclude(error_message='')
        elif value is False:
            return queryset.filter(models.Q(error_message__isnull=True) | models.Q(error_message=''))
        return queryset
    
    def filter_created_today(self, queryset, name, value):
        """Filter by created today."""
        if value is True:
            today = timezone.now().date()
            return queryset.filter(created_at__date=today)
        return queryset
    
    def filter_created_this_week(self, queryset, name, value):
        """Filter by created this week."""
        if value is True:
            today = timezone.now().date()
            start_week = today - timedelta(days=today.weekday())
            return queryset.filter(created_at__date__gte=start_week)
        return queryset
    
    def filter_created_this_month(self, queryset, name, value):
        """Filter by created this month."""
        if value is True:
            today = timezone.now().date()
            start_month = today.replace(day=1)
            return queryset.filter(created_at__date__gte=start_month)
        return queryset


class AvailFilter(django_filters.FilterSet):
    """Filter for Avail model."""
    
    # Window filters
    window = django_filters.ModelChoiceFilter(
        field_name='window',
        queryset=Window.objects.all(),
        label='Window'
    )
    
    # Time filters
    avail_start = django_filters.CharFilter(
        field_name='avail_start',
        lookup_expr='icontains',
        label='Avail start contains'
    )
    
    avail_in_window = django_filters.CharFilter(
        field_name='avail_in_window',
        lookup_expr='icontains',
        label='Avail in window contains'
    )
    
    # Date filters
    created_after = django_filters.DateTimeFilter(
        field_name='created_at',
        lookup_expr='gte',
        label='Created after'
    )
    
    created_before = django_filters.DateTimeFilter(
        field_name='created_at',
        lookup_expr='lte',
        label='Created before'
    )
    
    created_date_range = django_filters.DateFromToRangeFilter(
        field_name='created_at',
        label='Created date range'
    )
    
    # Custom filters
    has_adspots = django_filters.BooleanFilter(
        method='filter_has_adspots',
        label='Has adspots'
    )
    
    adspot_count_min = django_filters.NumberFilter(
        method='filter_adspot_count_min',
        label='Minimum adspot count'
    )
    
    adspot_count_max = django_filters.NumberFilter(
        method='filter_adspot_count_max',
        label='Maximum adspot count'
    )
    
    class Meta:
        model = Avail
        fields = {
            'window': ['exact'],
            'avail_start': ['exact', 'icontains'],
            'avail_in_window': ['exact', 'icontains'],
            'created_at': ['exact', 'gte', 'lte', 'date'],
            'updated_at': ['exact', 'gte', 'lte', 'date'],
        }
    
    def filter_has_adspots(self, queryset, name, value):
        """Filter by presence of adspots."""
        if value is True:
            return queryset.filter(adspot_placements__isnull=False).distinct()
        elif value is False:
            return queryset.filter(adspot_placements__isnull=True)
        return queryset
    
    def filter_adspot_count_min(self, queryset, name, value):
        """Filter by minimum adspot count."""
        if value is not None:
            return queryset.annotate(
                adspot_count=models.Count('adspot_placements')
            ).filter(adspot_count__gte=value)
        return queryset
    
    def filter_adspot_count_max(self, queryset, name, value):
        """Filter by maximum adspot count."""
        if value is not None:
            return queryset.annotate(
                adspot_count=models.Count('adspot_placements')
            ).filter(adspot_count__lte=value)
        return queryset


class WindowFilter(django_filters.FilterSet):
    """Filter for Window model."""
    
    # Playlist filters
    playlist = django_filters.CharFilter(
        field_name='playlist',
        label='Playlist ID'
    )
    
    # Time filters
    window_start = django_filters.CharFilter(
        field_name='window_start',
        lookup_expr='icontains',
        label='Window start contains'
    )
    
    window_end = django_filters.CharFilter(
        field_name='window_end',
        lookup_expr='icontains',
        label='Window end contains'
    )
    
    window_duration = django_filters.CharFilter(
        field_name='window_duration',
        lookup_expr='icontains',
        label='Window duration contains'
    )
    
    # Date filters
    created_after = django_filters.DateTimeFilter(
        field_name='created_at',
        lookup_expr='gte',
        label='Created after'
    )
    
    created_before = django_filters.DateTimeFilter(
        field_name='created_at',
        lookup_expr='lte',
        label='Created before'
    )
    
    created_date_range = django_filters.DateFromToRangeFilter(
        field_name='created_at',
        label='Created date range'
    )
    
    # Custom filters
    has_avails = django_filters.BooleanFilter(
        method='filter_has_avails',
        label='Has avails'
    )
    
    avail_count_min = django_filters.NumberFilter(
        method='filter_avail_count_min',
        label='Minimum avail count'
    )
    
    avail_count_max = django_filters.NumberFilter(
        method='filter_avail_count_max',
        label='Maximum avail count'
    )
    
    class Meta:
        model = Window
        fields = {
            'playlist': ['exact'],
            'window_start': ['exact', 'icontains'],
            'window_end': ['exact', 'icontains'],
            'window_duration': ['exact', 'icontains'],
            'created_at': ['exact', 'gte', 'lte', 'date'],
            'updated_at': ['exact', 'gte', 'lte', 'date'],
        }
    
    def filter_has_avails(self, queryset, name, value):
        """Filter by presence of avails."""
        if value is True:
            return queryset.filter(avails__isnull=False).distinct()
        elif value is False:
            return queryset.filter(avails__isnull=True)
        return queryset
    
    def filter_avail_count_min(self, queryset, name, value):
        """Filter by minimum avail count."""
        if value is not None:
            return queryset.annotate(
                avail_count=models.Count('avails')
            ).filter(avail_count__gte=value)
        return queryset
    
    def filter_avail_count_max(self, queryset, name, value):
        """Filter by maximum avail count."""
        if value is not None:
            return queryset.annotate(
                avail_count=models.Count('avails')
            ).filter(avail_count__lte=value)
        return queryset


class AdspotInAvailFilter(django_filters.FilterSet):
    """Filter for AdspotInAvail model."""
    
    # Relationship filters
    avail = django_filters.ModelChoiceFilter(
        field_name='avail',
        queryset=Avail.objects.all(),
        label='Avail'
    )
    
    adspot = django_filters.ModelChoiceFilter(
        field_name='adspot',
        queryset=Adspot.objects.all(),
        label='Adspot'
    )
    
    # Position filters
    position_in_avail = django_filters.NumberFilter(
        field_name='position_in_avail',
        label='Position in avail'
    )
    
    position_min = django_filters.NumberFilter(
        field_name='position_in_avail',
        lookup_expr='gte',
        label='Minimum position'
    )
    
    position_max = django_filters.NumberFilter(
        field_name='position_in_avail',
        lookup_expr='lte',
        label='Maximum position'
    )
    
    # Traffic ID filters
    traffic_id = django_filters.NumberFilter(
        field_name='traffic_id',
        label='Traffic ID'
    )
    
    # Date filters
    created_after = django_filters.DateTimeFilter(
        field_name='created_at',
        lookup_expr='gte',
        label='Created after'
    )
    
    created_before = django_filters.DateTimeFilter(
        field_name='created_at',
        lookup_expr='lte',
        label='Created before'
    )
    
    created_date_range = django_filters.DateFromToRangeFilter(
        field_name='created_at',
        label='Created date range'
    )
    
    # Adspot-related filters
    adspot_campaign = django_filters.ModelChoiceFilter(
        field_name='adspot__campaign',
        queryset=Campaign.objects.all(),
        label='Adspot Campaign'
    )
    
    adspot_brand = django_filters.ModelChoiceFilter(
        field_name='adspot__brand',
        queryset=Brand.objects.all(),
        label='Adspot Brand'
    )
    
    adspot_processing_status = django_filters.ChoiceFilter(
        field_name='adspot__processing_status',
        choices=Adspot.PROCESSING_STATUS_CHOICES,
        label='Adspot Processing Status'
    )
    
    class Meta:
        model = AdspotInAvail
        fields = {
            'avail': ['exact'],
            'adspot': ['exact'],
            'position_in_avail': ['exact', 'gte', 'lte'],
            'traffic_id': ['exact'],
            'created_at': ['exact', 'gte', 'lte', 'date'],
            'updated_at': ['exact', 'gte', 'lte', 'date'],
        }


class PendingFilter(django_filters.FilterSet):
    """Filter for Pending model."""
    
    # Text search filters
    creative_id = django_filters.CharFilter(
        field_name='creative_id',
        lookup_expr='icontains',
        label='Creative ID contains'
    )
    
    url = django_filters.CharFilter(
        field_name='url',
        lookup_expr='icontains',
        label='URL contains'
    )
    
    # Status filters
    status = django_filters.ChoiceFilter(
        field_name='status',
        choices=Pending.PENDING_STATUS_CHOICES,
        label='Status'
    )
    
    # Duration filters
    duration = django_filters.CharFilter(
        field_name='duration',
        lookup_expr='icontains',
        label='Duration contains'
    )
    
    # Date filters
    created_after = django_filters.DateTimeFilter(
        field_name='created_at',
        lookup_expr='gte',
        label='Created after'
    )
    
    created_before = django_filters.DateTimeFilter(
        field_name='created_at',
        lookup_expr='lte',
        label='Created before'
    )
    
    created_date_range = django_filters.DateFromToRangeFilter(
        field_name='created_at',
        label='Created date range'
    )
    
    # Custom filters
    has_error = django_filters.BooleanFilter(
        method='filter_has_error',
        label='Has error message'
    )
    
    # Time-based filters
    created_today = django_filters.BooleanFilter(
        method='filter_created_today',
        label='Created today'
    )
    
    created_this_week = django_filters.BooleanFilter(
        method='filter_created_this_week',
        label='Created this week'
    )
    
    class Meta:
        model = Pending
        fields = {
            'creative_id': ['exact', 'icontains'],
            'url': ['exact', 'icontains'],
            'status': ['exact'],
            'duration': ['exact', 'icontains'],
            'created_at': ['exact', 'gte', 'lte', 'date'],
            'updated_at': ['exact', 'gte', 'lte', 'date'],
        }
    
    def filter_has_error(self, queryset, name, value):
        """Filter by presence of error message."""
        if value is True:
            return queryset.exclude(error_message__isnull=True).exclude(error_message='')
        elif value is False:
            return queryset.filter(models.Q(error_message__isnull=True) | models.Q(error_message=''))
        return queryset
    
    def filter_created_today(self, queryset, name, value):
        """Filter by created today."""
        if value is True:
            today = timezone.now().date()
            return queryset.filter(created_at__date=today)
        return queryset
    
    def filter_created_this_week(self, queryset, name, value):
        """Filter by created this week."""
        if value is True:
            today = timezone.now().date()
            start_week = today - timedelta(days=today.weekday())
            return queryset.filter(created_at__date__gte=start_week)
        return queryset