"""Channels Filters

This module contains filter classes for channel management functionality.
It provides comprehensive filtering capabilities for API endpoints and
list views using django-filter.

Filters:
    - ChannelFilter: Advanced filtering for channels
    - ChannelZoneFilter: Filtering for channel zones
    - ChannelCodecFilter: Filtering for codec configurations
    - JingleFilter: Filtering for jingles
    - DayTimeFilter: Filtering for time slots

Features:
- Text search across multiple fields
- Relationship filtering
- Date range filtering
- Numerical range filtering
- Boolean filtering
- Choice field filtering
- Custom filter methods
"""

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

from .models import Channel, ChannelZone, ChannelCodec, Jingle, DayTime


class ChannelFilter(django_filters.FilterSet):
    """Filter class for Channel model.
    
    Provides comprehensive filtering options for channels including
    text search, provider filtering, technical specifications,
    and date range filtering.
    """
    
    # Text search filters
    search = django_filters.CharFilter(
        method='filter_search',
        label='Search',
        help_text='Search in name, channel code, and description'
    )
    
    name = django_filters.CharFilter(
        lookup_expr='icontains',
        label='Channel Name',
        help_text='Filter by channel name (case-insensitive)'
    )
    
    channel_code = django_filters.CharFilter(
        lookup_expr='icontains',
        label='Channel Code',
        help_text='Filter by channel code (case-insensitive)'
    )
    
    # Provider and region filters
    provider = django_filters.ChoiceFilter(
        choices=Channel.PROVIDER_CHOICES,
        label='Provider',
        help_text='Filter by broadcast provider'
    )
    
    region = django_filters.CharFilter(
        lookup_expr='icontains',
        label='Region',
        help_text='Filter by broadcasting region'
    )
    
    # Technical specification filters
    is_hd = django_filters.BooleanFilter(
        label='HD Support',
        help_text='Filter channels with HD support'
    )
    
    is_4k = django_filters.BooleanFilter(
        label='4K Support',
        help_text='Filter channels with 4K support'
    )
    
    default_codec = django_filters.ChoiceFilter(
        choices=Channel.CODEC_CHOICES,
        label='Default Codec',
        help_text='Filter by default video codec'
    )
    
    audio_codec = django_filters.ChoiceFilter(
        choices=Channel.AUDIO_CODEC_CHOICES,
        label='Audio Codec',
        help_text='Filter by audio codec'
    )
    
    resolution = django_filters.ChoiceFilter(
        choices=Channel.RESOLUTION_CHOICES,
        label='Resolution',
        help_text='Filter by default resolution'
    )
    
    # Bitrate range filters
    bitrate_min = django_filters.NumberFilter(
        field_name='bitrate',
        lookup_expr='gte',
        label='Minimum Bitrate',
        help_text='Minimum bitrate in kbps'
    )
    
    bitrate_max = django_filters.NumberFilter(
        field_name='bitrate',
        lookup_expr='lte',
        label='Maximum Bitrate',
        help_text='Maximum bitrate in kbps'
    )
    
    bitrate_range = django_filters.RangeFilter(
        field_name='bitrate',
        label='Bitrate Range',
        help_text='Bitrate range in kbps (min,max)'
    )
    
    # Frame rate filters
    frame_rate_min = django_filters.NumberFilter(
        field_name='frame_rate',
        lookup_expr='gte',
        label='Minimum Frame Rate',
        help_text='Minimum frame rate in fps'
    )
    
    frame_rate_max = django_filters.NumberFilter(
        field_name='frame_rate',
        lookup_expr='lte',
        label='Maximum Frame Rate',
        help_text='Maximum frame rate in fps'
    )
    
    # Language filter
    language = django_filters.CharFilter(
        lookup_expr='iexact',
        label='Language',
        help_text='Filter by language code'
    )
    
    # Status filter
    status = django_filters.ChoiceFilter(
        choices=[('active', 'Active'), ('inactive', 'Inactive')],
        label='Status',
        help_text='Filter by channel status'
    )
    
    # Date range filters
    created_after = django_filters.DateTimeFilter(
        field_name='created_at',
        lookup_expr='gte',
        label='Created After',
        help_text='Show channels created after this date'
    )
    
    created_before = django_filters.DateTimeFilter(
        field_name='created_at',
        lookup_expr='lte',
        label='Created Before',
        help_text='Show channels created before this date'
    )
    
    created_date_range = django_filters.DateFromToRangeFilter(
        field_name='created_at',
        label='Created Date Range',
        help_text='Date range for channel creation'
    )
    
    # Relationship filters
    has_zones = django_filters.BooleanFilter(
        method='filter_has_zones',
        label='Has Zones',
        help_text='Filter channels that have zones configured'
    )
    
    has_jingles = django_filters.BooleanFilter(
        method='filter_has_jingles',
        label='Has Jingles',
        help_text='Filter channels that have jingles'
    )
    
    has_codecs = django_filters.BooleanFilter(
        method='filter_has_codecs',
        label='Has Codecs',
        help_text='Filter channels that have codec configurations'
    )
    
    # Zone count filters
    zone_count_min = django_filters.NumberFilter(
        method='filter_zone_count_min',
        label='Minimum Zone Count',
        help_text='Minimum number of zones'
    )
    
    zone_count_max = django_filters.NumberFilter(
        method='filter_zone_count_max',
        label='Maximum Zone Count',
        help_text='Maximum number of zones'
    )
    
    class Meta:
        model = Channel
        fields = {
            'name': ['exact', 'icontains', 'istartswith'],
            'channel_code': ['exact', 'icontains'],
            'provider': ['exact'],
            'status': ['exact'],
            'is_hd': ['exact'],
            'is_4k': ['exact'],
            'created_at': ['exact', 'gte', 'lte'],
            'updated_at': ['exact', 'gte', 'lte'],
        }
    
    def filter_search(self, queryset, name, value):
        """Custom search filter across multiple fields."""
        if not value:
            return queryset
        
        return queryset.filter(
            models.Q(name__icontains=value) |
            models.Q(channel_code__icontains=value) |
            models.Q(description__icontains=value) |
            models.Q(provider__icontains=value)
        )
    
    def filter_has_zones(self, queryset, name, value):
        """Filter channels that have zones."""
        if value is True:
            return queryset.filter(zones__isnull=False).distinct()
        elif value is False:
            return queryset.filter(zones__isnull=True)
        return queryset
    
    def filter_has_jingles(self, queryset, name, value):
        """Filter channels that have jingles."""
        if value is True:
            return queryset.filter(jingles__isnull=False).distinct()
        elif value is False:
            return queryset.filter(jingles__isnull=True)
        return queryset
    
    def filter_has_codecs(self, queryset, name, value):
        """Filter channels that have codec configurations."""
        if value is True:
            return queryset.filter(codecs__isnull=False).distinct()
        elif value is False:
            return queryset.filter(codecs__isnull=True)
        return queryset
    
    def filter_zone_count_min(self, queryset, name, value):
        """Filter by minimum zone count."""
        if value is not None:
            return queryset.annotate(
                zone_count=models.Count('zones')
            ).filter(zone_count__gte=value)
        return queryset
    
    def filter_zone_count_max(self, queryset, name, value):
        """Filter by maximum zone count."""
        if value is not None:
            return queryset.annotate(
                zone_count=models.Count('zones')
            ).filter(zone_count__lte=value)
        return queryset


class ChannelZoneFilter(django_filters.FilterSet):
    """Filter class for ChannelZone model.
    
    Provides filtering options for channel zones including
    channel relationship, region, and time-based filtering.
    """
    
    # Text search
    search = django_filters.CharFilter(
        method='filter_search',
        label='Search',
        help_text='Search in zone name, region name, and description'
    )
    
    # Channel relationship
    channel = django_filters.ModelChoiceFilter(
        queryset=Channel.objects.all(),
        label='Channel',
        help_text='Filter by channel'
    )
    
    channel_name = django_filters.CharFilter(
        field_name='channel__name',
        lookup_expr='icontains',
        label='Channel Name',
        help_text='Filter by channel name'
    )
    
    # Zone information
    zone_name = django_filters.CharFilter(
        lookup_expr='icontains',
        label='Zone Name',
        help_text='Filter by zone name'
    )
    
    region_name = django_filters.CharFilter(
        lookup_expr='icontains',
        label='Region Name',
        help_text='Filter by region name'
    )
    
    # Primary zone filter
    is_primary = django_filters.BooleanFilter(
        label='Primary Zone',
        help_text='Filter primary zones'
    )
    
    # Time offset filters
    time_offset_min = django_filters.NumberFilter(
        field_name='time_offset',
        lookup_expr='gte',
        label='Minimum Time Offset',
        help_text='Minimum time offset in minutes'
    )
    
    time_offset_max = django_filters.NumberFilter(
        field_name='time_offset',
        lookup_expr='lte',
        label='Maximum Time Offset',
        help_text='Maximum time offset in minutes'
    )
    
    # Status filter
    status = django_filters.ChoiceFilter(
        choices=[('active', 'Active'), ('inactive', 'Inactive')],
        label='Status',
        help_text='Filter by zone status'
    )
    
    class Meta:
        model = ChannelZone
        fields = {
            'zone_name': ['exact', 'icontains'],
            'region_name': ['exact', 'icontains'],
            'is_primary': ['exact'],
            'status': ['exact'],
            'created_at': ['gte', 'lte'],
        }
    
    def filter_search(self, queryset, name, value):
        """Custom search filter across multiple fields."""
        if not value:
            return queryset
        
        return queryset.filter(
            models.Q(zone_name__icontains=value) |
            models.Q(region_name__icontains=value) |
            models.Q(description__icontains=value) |
            models.Q(channel__name__icontains=value)
        )


class ChannelCodecFilter(django_filters.FilterSet):
    """Filter class for ChannelCodec model.
    
    Provides filtering options for codec configurations including
    quality levels, codec types, and technical specifications.
    """
    
    # Channel relationship
    channel = django_filters.ModelChoiceFilter(
        queryset=Channel.objects.all(),
        label='Channel',
        help_text='Filter by channel'
    )
    
    # Quality and codec filters
    quality_level = django_filters.ChoiceFilter(
        choices=ChannelCodec.QUALITY_CHOICES,
        label='Quality Level',
        help_text='Filter by quality level'
    )
    
    video_codec = django_filters.ChoiceFilter(
        choices=Channel.CODEC_CHOICES,
        label='Video Codec',
        help_text='Filter by video codec'
    )
    
    audio_codec = django_filters.ChoiceFilter(
        choices=Channel.AUDIO_CODEC_CHOICES,
        label='Audio Codec',
        help_text='Filter by audio codec'
    )
    
    resolution = django_filters.ChoiceFilter(
        choices=Channel.RESOLUTION_CHOICES,
        label='Resolution',
        help_text='Filter by resolution'
    )
    
    # Bitrate filters
    bitrate_range = django_filters.RangeFilter(
        field_name='bitrate',
        label='Bitrate Range',
        help_text='Video bitrate range in kbps'
    )
    
    audio_bitrate_range = django_filters.RangeFilter(
        field_name='audio_bitrate',
        label='Audio Bitrate Range',
        help_text='Audio bitrate range in kbps'
    )
    
    # Frame rate filters
    frame_rate_range = django_filters.RangeFilter(
        field_name='frame_rate',
        label='Frame Rate Range',
        help_text='Frame rate range in fps'
    )
    
    # Default codec filter
    is_default = django_filters.BooleanFilter(
        label='Default Codec',
        help_text='Filter default codec configurations'
    )
    
    class Meta:
        model = ChannelCodec
        fields = {
            'quality_level': ['exact'],
            'video_codec': ['exact'],
            'audio_codec': ['exact'],
            'resolution': ['exact'],
            'is_default': ['exact'],
            'status': ['exact'],
        }


class JingleFilter(django_filters.FilterSet):
    """Filter class for Jingle model.
    
    Provides filtering options for jingles including
    channel relationship, jingle types, and audio specifications.
    """
    
    # Text search
    search = django_filters.CharFilter(
        method='filter_search',
        label='Search',
        help_text='Search in jingle name and description'
    )
    
    # Channel relationship
    channel = django_filters.ModelChoiceFilter(
        queryset=Channel.objects.all(),
        label='Channel',
        help_text='Filter by channel'
    )
    
    channel_name = django_filters.CharFilter(
        field_name='channel__name',
        lookup_expr='icontains',
        label='Channel Name',
        help_text='Filter by channel name'
    )
    
    # Jingle information
    name = django_filters.CharFilter(
        lookup_expr='icontains',
        label='Jingle Name',
        help_text='Filter by jingle name'
    )
    
    # Jingle type filters
    is_intro = django_filters.BooleanFilter(
        label='Intro Jingle',
        help_text='Filter intro jingles'
    )
    
    is_outro = django_filters.BooleanFilter(
        label='Outro Jingle',
        help_text='Filter outro jingles'
    )
    
    is_transition = django_filters.BooleanFilter(
        label='Transition Jingle',
        help_text='Filter transition jingles'
    )
    
    jingle_type = django_filters.CharFilter(
        method='filter_jingle_type',
        label='Jingle Type',
        help_text='Filter by jingle type (intro, outro, transition)'
    )
    
    # Audio specifications
    audio_format = django_filters.ChoiceFilter(
        choices=Jingle.AUDIO_FORMAT_CHOICES,
        label='Audio Format',
        help_text='Filter by audio format'
    )
    
    # Duration filters
    duration_min = django_filters.NumberFilter(
        field_name='duration',
        lookup_expr='gte',
        label='Minimum Duration',
        help_text='Minimum duration in seconds'
    )
    
    duration_max = django_filters.NumberFilter(
        field_name='duration',
        lookup_expr='lte',
        label='Maximum Duration',
        help_text='Maximum duration in seconds'
    )
    
    duration_range = django_filters.RangeFilter(
        field_name='duration',
        label='Duration Range',
        help_text='Duration range in seconds'
    )
    
    # File size filters
    file_size_min = django_filters.NumberFilter(
        field_name='file_size',
        lookup_expr='gte',
        label='Minimum File Size',
        help_text='Minimum file size in bytes'
    )
    
    file_size_max = django_filters.NumberFilter(
        field_name='file_size',
        lookup_expr='lte',
        label='Maximum File Size',
        help_text='Maximum file size in bytes'
    )
    
    # Bitrate and sample rate filters
    bitrate_range = django_filters.RangeFilter(
        field_name='bitrate',
        label='Bitrate Range',
        help_text='Audio bitrate range in kbps'
    )
    
    sample_rate = django_filters.NumberFilter(
        label='Sample Rate',
        help_text='Audio sample rate in Hz'
    )
    
    # Play order filters
    play_order_min = django_filters.NumberFilter(
        field_name='play_order',
        lookup_expr='gte',
        label='Minimum Play Order',
        help_text='Minimum play order'
    )
    
    play_order_max = django_filters.NumberFilter(
        field_name='play_order',
        lookup_expr='lte',
        label='Maximum Play Order',
        help_text='Maximum play order'
    )
    
    class Meta:
        model = Jingle
        fields = {
            'name': ['exact', 'icontains'],
            'audio_format': ['exact'],
            'is_intro': ['exact'],
            'is_outro': ['exact'],
            'is_transition': ['exact'],
            'status': ['exact'],
            'created_at': ['gte', 'lte'],
        }
    
    def filter_search(self, queryset, name, value):
        """Custom search filter across multiple fields."""
        if not value:
            return queryset
        
        return queryset.filter(
            models.Q(name__icontains=value) |
            models.Q(description__icontains=value) |
            models.Q(channel__name__icontains=value)
        )
    
    def filter_jingle_type(self, queryset, name, value):
        """Filter by jingle type."""
        if not value:
            return queryset
        
        value = value.lower()
        if value == 'intro':
            return queryset.filter(is_intro=True)
        elif value == 'outro':
            return queryset.filter(is_outro=True)
        elif value == 'transition':
            return queryset.filter(is_transition=True)
        
        return queryset


class DayTimeFilter(django_filters.FilterSet):
    """Filter class for DayTime model.
    
    Provides filtering options for time slots including
    day of week, time ranges, and priority levels.
    """
    
    # Text search
    search = django_filters.CharFilter(
        method='filter_search',
        label='Search',
        help_text='Search in time slot name and description'
    )
    
    # Time slot information
    name = django_filters.CharFilter(
        lookup_expr='icontains',
        label='Time Slot Name',
        help_text='Filter by time slot name'
    )
    
    # Day of week filter
    day_of_week = django_filters.ChoiceFilter(
        choices=DayTime.DAY_CHOICES,
        label='Day of Week',
        help_text='Filter by day of week'
    )
    
    # Time range filters
    start_time_after = django_filters.TimeFilter(
        field_name='start_time',
        lookup_expr='gte',
        label='Start Time After',
        help_text='Start time after specified time'
    )
    
    start_time_before = django_filters.TimeFilter(
        field_name='start_time',
        lookup_expr='lte',
        label='Start Time Before',
        help_text='Start time before specified time'
    )
    
    end_time_after = django_filters.TimeFilter(
        field_name='end_time',
        lookup_expr='gte',
        label='End Time After',
        help_text='End time after specified time'
    )
    
    end_time_before = django_filters.TimeFilter(
        field_name='end_time',
        lookup_expr='lte',
        label='End Time Before',
        help_text='End time before specified time'
    )
    
    # Special time filters
    is_prime_time = django_filters.BooleanFilter(
        label='Prime Time',
        help_text='Filter prime time slots'
    )
    
    is_weekend = django_filters.BooleanFilter(
        label='Weekend',
        help_text='Filter weekend time slots'
    )
    
    # Priority filters
    priority_min = django_filters.NumberFilter(
        field_name='priority',
        lookup_expr='gte',
        label='Minimum Priority',
        help_text='Minimum priority level'
    )
    
    priority_max = django_filters.NumberFilter(
        field_name='priority',
        lookup_expr='lte',
        label='Maximum Priority',
        help_text='Maximum priority level'
    )
    
    priority_range = django_filters.RangeFilter(
        field_name='priority',
        label='Priority Range',
        help_text='Priority level range'
    )
    
    # Duration filter
    duration_min = django_filters.NumberFilter(
        method='filter_duration_min',
        label='Minimum Duration',
        help_text='Minimum duration in minutes'
    )
    
    duration_max = django_filters.NumberFilter(
        method='filter_duration_max',
        label='Maximum Duration',
        help_text='Maximum duration in minutes'
    )
    
    class Meta:
        model = DayTime
        fields = {
            'name': ['exact', 'icontains'],
            'day_of_week': ['exact'],
            'is_prime_time': ['exact'],
            'is_weekend': ['exact'],
            'priority': ['exact', 'gte', 'lte'],
            'status': ['exact'],
        }
    
    def filter_search(self, queryset, name, value):
        """Custom search filter across multiple fields."""
        if not value:
            return queryset
        
        return queryset.filter(
            models.Q(name__icontains=value) |
            models.Q(description__icontains=value)
        )
    
    def filter_duration_min(self, queryset, name, value):
        """Filter by minimum duration."""
        if value is not None:
            # This would require a custom property or annotation
            # For now, we'll return the queryset as-is
            return queryset
        return queryset
    
    def filter_duration_max(self, queryset, name, value):
        """Filter by maximum duration."""
        if value is not None:
            # This would require a custom property or annotation
            # For now, we'll return the queryset as-is
            return queryset
        return queryset