"""Filters for Jingles app."""

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

from .models import (
    JingleCategory,
    JingleType,
    Jingle,
    JinglePlaylist,
    JinglePlaylistItem,
    JingleSchedule,
)
from apps.channels.models import Channel


class JingleFilter(django_filters.FilterSet):
    """Filter for Jingle model."""
    
    # Basic filters
    name = django_filters.CharFilter(
        field_name='name',
        lookup_expr='icontains',
        help_text='Filter by jingle name (case-insensitive)'
    )
    description = django_filters.CharFilter(
        field_name='description',
        lookup_expr='icontains',
        help_text='Filter by description (case-insensitive)'
    )
    tags = django_filters.CharFilter(
        field_name='tags',
        lookup_expr='icontains',
        help_text='Filter by tags (case-insensitive)'
    )
    
    # Relationship filters
    channel = django_filters.ModelChoiceFilter(
        queryset=Channel.objects.filter(is_active=True),
        help_text='Filter by channel'
    )
    channel_name = django_filters.CharFilter(
        field_name='channel__name',
        lookup_expr='icontains',
        help_text='Filter by channel name (case-insensitive)'
    )
    category = django_filters.ModelChoiceFilter(
        queryset=JingleCategory.objects.filter(is_active=True),
        help_text='Filter by category'
    )
    category_name = django_filters.CharFilter(
        field_name='category__name',
        lookup_expr='icontains',
        help_text='Filter by category name (case-insensitive)'
    )
    jingle_type = django_filters.ModelChoiceFilter(
        queryset=JingleType.objects.filter(is_active=True),
        help_text='Filter by jingle type'
    )
    jingle_type_usage = django_filters.ChoiceFilter(
        field_name='jingle_type__usage',
        choices=JingleType.USAGE_CHOICES,
        help_text='Filter by jingle type usage'
    )
    
    # Status and quality filters
    status = django_filters.ChoiceFilter(
        choices=Jingle.STATUS_CHOICES,
        help_text='Filter by status'
    )
    quality = django_filters.ChoiceFilter(
        choices=Jingle.QUALITY_CHOICES,
        help_text='Filter by quality'
    )
    is_active = django_filters.BooleanFilter(
        help_text='Filter by active status'
    )
    is_deleted = django_filters.BooleanFilter(
        help_text='Filter by deleted status'
    )
    
    # File type filters
    file_format = django_filters.CharFilter(
        field_name='file_format',
        lookup_expr='iexact',
        help_text='Filter by file format (e.g., mp3, mp4)'
    )
    is_video = django_filters.BooleanFilter(
        method='filter_is_video',
        help_text='Filter video jingles'
    )
    is_audio = django_filters.BooleanFilter(
        method='filter_is_audio',
        help_text='Filter audio jingles'
    )
    
    # Duration filters
    duration_min = django_filters.NumberFilter(
        field_name='duration_seconds',
        lookup_expr='gte',
        help_text='Minimum duration in seconds'
    )
    duration_max = django_filters.NumberFilter(
        field_name='duration_seconds',
        lookup_expr='lte',
        help_text='Maximum duration in seconds'
    )
    duration_range = django_filters.RangeFilter(
        field_name='duration_seconds',
        help_text='Duration range in seconds (min,max)'
    )
    
    # File size filters
    file_size_min = django_filters.NumberFilter(
        field_name='file_size',
        lookup_expr='gte',
        help_text='Minimum file size in bytes'
    )
    file_size_max = django_filters.NumberFilter(
        field_name='file_size',
        lookup_expr='lte',
        help_text='Maximum file size in bytes'
    )
    
    # Priority filters
    priority = django_filters.NumberFilter(
        help_text='Filter by priority level'
    )
    priority_min = django_filters.NumberFilter(
        field_name='priority',
        lookup_expr='gte',
        help_text='Minimum priority level'
    )
    priority_max = django_filters.NumberFilter(
        field_name='priority',
        lookup_expr='lte',
        help_text='Maximum priority level'
    )
    
    # Play count filters
    play_count_min = django_filters.NumberFilter(
        field_name='play_count',
        lookup_expr='gte',
        help_text='Minimum play count'
    )
    play_count_max = django_filters.NumberFilter(
        field_name='play_count',
        lookup_expr='lte',
        help_text='Maximum play count'
    )
    never_played = django_filters.BooleanFilter(
        method='filter_never_played',
        help_text='Filter jingles that have never been played'
    )
    
    # Date filters
    created_after = django_filters.DateFilter(
        field_name='created_at',
        lookup_expr='gte',
        help_text='Created after date (YYYY-MM-DD)'
    )
    created_before = django_filters.DateFilter(
        field_name='created_at',
        lookup_expr='lte',
        help_text='Created before date (YYYY-MM-DD)'
    )
    created_date_range = django_filters.DateRangeFilter(
        field_name='created_at',
        help_text='Created date range'
    )
    
    start_date_after = django_filters.DateFilter(
        field_name='start_date',
        lookup_expr='gte',
        help_text='Start date after (YYYY-MM-DD)'
    )
    start_date_before = django_filters.DateFilter(
        field_name='start_date',
        lookup_expr='lte',
        help_text='Start date before (YYYY-MM-DD)'
    )
    end_date_after = django_filters.DateFilter(
        field_name='end_date',
        lookup_expr='gte',
        help_text='End date after (YYYY-MM-DD)'
    )
    end_date_before = django_filters.DateFilter(
        field_name='end_date',
        lookup_expr='lte',
        help_text='End date before (YYYY-MM-DD)'
    )
    
    last_played_after = django_filters.DateTimeFilter(
        field_name='last_played',
        lookup_expr='gte',
        help_text='Last played after datetime'
    )
    last_played_before = django_filters.DateTimeFilter(
        field_name='last_played',
        lookup_expr='lte',
        help_text='Last played before datetime'
    )
    
    # User filters
    uploaded_by = django_filters.CharFilter(
        field_name='uploaded_by__username',
        lookup_expr='icontains',
        help_text='Filter by uploader username'
    )
    approved_by = django_filters.CharFilter(
        field_name='approved_by__username',
        lookup_expr='icontains',
        help_text='Filter by approver username'
    )
    
    # Custom filters
    available = django_filters.BooleanFilter(
        method='filter_available',
        help_text='Filter available jingles (active, approved, not expired)'
    )
    expired = django_filters.BooleanFilter(
        method='filter_expired',
        help_text='Filter expired jingles'
    )
    pending_approval = django_filters.BooleanFilter(
        method='filter_pending_approval',
        help_text='Filter jingles pending approval'
    )
    recently_uploaded = django_filters.BooleanFilter(
        method='filter_recently_uploaded',
        help_text='Filter jingles uploaded in the last 7 days'
    )
    popular = django_filters.BooleanFilter(
        method='filter_popular',
        help_text='Filter popular jingles (top 20% by play count)'
    )
    
    class Meta:
        model = Jingle
        fields = {
            'id': ['exact', 'in'],
            'name': ['exact', 'icontains'],
            'status': ['exact', 'in'],
            'quality': ['exact', 'in'],
            'is_active': ['exact'],
            'priority': ['exact', 'lt', 'lte', 'gt', 'gte'],
            'play_count': ['exact', 'lt', 'lte', 'gt', 'gte'],
            'duration_seconds': ['exact', 'lt', 'lte', 'gt', 'gte'],
            'file_size': ['exact', 'lt', 'lte', 'gt', 'gte'],
            'created_at': ['exact', 'date', 'date__gte', 'date__lte'],
            'updated_at': ['exact', 'date', 'date__gte', 'date__lte'],
        }
    
    def filter_is_video(self, queryset, name, value):
        """Filter video jingles."""
        if value:
            video_formats = ['mp4', 'mov', 'avi', 'mkv', 'webm']
            return queryset.filter(file_format__in=video_formats)
        else:
            video_formats = ['mp4', 'mov', 'avi', 'mkv', 'webm']
            return queryset.exclude(file_format__in=video_formats)
    
    def filter_is_audio(self, queryset, name, value):
        """Filter audio jingles."""
        if value:
            audio_formats = ['mp3', 'wav', 'aac', 'ogg', 'flac']
            return queryset.filter(file_format__in=audio_formats)
        else:
            audio_formats = ['mp3', 'wav', 'aac', 'ogg', 'flac']
            return queryset.exclude(file_format__in=audio_formats)
    
    def filter_never_played(self, queryset, name, value):
        """Filter jingles that have never been played."""
        if value:
            return queryset.filter(play_count=0)
        else:
            return queryset.filter(play_count__gt=0)
    
    def filter_available(self, queryset, name, value):
        """Filter available jingles."""
        if value:
            today = timezone.now().date()
            return queryset.filter(
                is_active=True,
                status='approved',
                is_deleted=False
            ).filter(
                Q(start_date__isnull=True) | Q(start_date__lte=today)
            ).filter(
                Q(end_date__isnull=True) | Q(end_date__gte=today)
            )
        return queryset
    
    def filter_expired(self, queryset, name, value):
        """Filter expired jingles."""
        if value:
            today = timezone.now().date()
            return queryset.filter(
                end_date__lt=today,
                is_active=True
            )
        return queryset
    
    def filter_pending_approval(self, queryset, name, value):
        """Filter jingles pending approval."""
        if value:
            return queryset.filter(status='pending')
        return queryset
    
    def filter_recently_uploaded(self, queryset, name, value):
        """Filter recently uploaded jingles."""
        if value:
            week_ago = timezone.now() - timedelta(days=7)
            return queryset.filter(created_at__gte=week_ago)
        return queryset
    
    def filter_popular(self, queryset, name, value):
        """Filter popular jingles."""
        if value:
            # Get top 20% by play count
            total_count = queryset.count()
            if total_count > 0:
                top_count = max(1, int(total_count * 0.2))
                top_jingles = queryset.order_by('-play_count')[:top_count]
                return queryset.filter(id__in=[j.id for j in top_jingles])
        return queryset


class JinglePlaylistFilter(django_filters.FilterSet):
    """Filter for JinglePlaylist model."""
    
    # Basic filters
    name = django_filters.CharFilter(
        field_name='name',
        lookup_expr='icontains',
        help_text='Filter by playlist name (case-insensitive)'
    )
    description = django_filters.CharFilter(
        field_name='description',
        lookup_expr='icontains',
        help_text='Filter by description (case-insensitive)'
    )
    
    # Relationship filters
    channel = django_filters.ModelChoiceFilter(
        queryset=Channel.objects.filter(is_active=True),
        help_text='Filter by channel'
    )
    channel_name = django_filters.CharFilter(
        field_name='channel__name',
        lookup_expr='icontains',
        help_text='Filter by channel name (case-insensitive)'
    )
    
    # Type and status filters
    playlist_type = django_filters.ChoiceFilter(
        choices=JinglePlaylist.PLAYLIST_TYPES,
        help_text='Filter by playlist type'
    )
    is_active = django_filters.BooleanFilter(
        help_text='Filter by active status'
    )
    
    # User filters
    created_by = django_filters.CharFilter(
        field_name='created_by__username',
        lookup_expr='icontains',
        help_text='Filter by creator username'
    )
    
    # Date filters
    created_after = django_filters.DateFilter(
        field_name='created_at',
        lookup_expr='gte',
        help_text='Created after date (YYYY-MM-DD)'
    )
    created_before = django_filters.DateFilter(
        field_name='created_at',
        lookup_expr='lte',
        help_text='Created before date (YYYY-MM-DD)'
    )
    
    # Time filters for scheduled playlists
    start_time_after = django_filters.TimeFilter(
        field_name='start_time',
        lookup_expr='gte',
        help_text='Start time after (HH:MM)'
    )
    start_time_before = django_filters.TimeFilter(
        field_name='start_time',
        lookup_expr='lte',
        help_text='Start time before (HH:MM)'
    )
    end_time_after = django_filters.TimeFilter(
        field_name='end_time',
        lookup_expr='gte',
        help_text='End time after (HH:MM)'
    )
    end_time_before = django_filters.TimeFilter(
        field_name='end_time',
        lookup_expr='lte',
        help_text='End time before (HH:MM)'
    )
    
    # Custom filters
    has_jingles = django_filters.BooleanFilter(
        method='filter_has_jingles',
        help_text='Filter playlists that have jingles'
    )
    empty = django_filters.BooleanFilter(
        method='filter_empty',
        help_text='Filter empty playlists'
    )
    scheduled_now = django_filters.BooleanFilter(
        method='filter_scheduled_now',
        help_text='Filter playlists scheduled for current time'
    )
    
    class Meta:
        model = JinglePlaylist
        fields = {
            'id': ['exact', 'in'],
            'name': ['exact', 'icontains'],
            'playlist_type': ['exact', 'in'],
            'is_active': ['exact'],
            'created_at': ['exact', 'date', 'date__gte', 'date__lte'],
            'updated_at': ['exact', 'date', 'date__gte', 'date__lte'],
        }
    
    def filter_has_jingles(self, queryset, name, value):
        """Filter playlists that have jingles."""
        if value:
            return queryset.filter(playlist_items__isnull=False).distinct()
        else:
            return queryset.filter(playlist_items__isnull=True)
    
    def filter_empty(self, queryset, name, value):
        """Filter empty playlists."""
        if value:
            return queryset.filter(playlist_items__isnull=True)
        else:
            return queryset.filter(playlist_items__isnull=False).distinct()
    
    def filter_scheduled_now(self, queryset, name, value):
        """Filter playlists scheduled for current time."""
        if value:
            now = timezone.now()
            current_time = now.time()
            current_weekday = now.weekday() + 1  # Monday = 1
            
            # Filter by time range
            time_filter = Q(
                start_time__lte=current_time,
                end_time__gte=current_time
            ) | Q(
                start_time__gt=F('end_time'),  # Overnight schedule
                start_time__lte=current_time
            ) | Q(
                start_time__gt=F('end_time'),  # Overnight schedule
                end_time__gte=current_time
            )
            
            # Filter by days of week
            day_filter = Q(days_of_week__isnull=True) | Q(
                days_of_week__icontains=str(current_weekday)
            )
            
            return queryset.filter(
                playlist_type='scheduled',
                is_active=True
            ).filter(time_filter).filter(day_filter)
        
        return queryset


class JinglePlaylistItemFilter(django_filters.FilterSet):
    """Filter for JinglePlaylistItem model."""
    
    # Relationship filters
    playlist = django_filters.ModelChoiceFilter(
        queryset=JinglePlaylist.objects.filter(is_active=True),
        help_text='Filter by playlist'
    )
    playlist_name = django_filters.CharFilter(
        field_name='playlist__name',
        lookup_expr='icontains',
        help_text='Filter by playlist name (case-insensitive)'
    )
    jingle = django_filters.ModelChoiceFilter(
        queryset=Jingle.objects.filter(is_deleted=False),
        help_text='Filter by jingle'
    )
    jingle_name = django_filters.CharFilter(
        field_name='jingle__name',
        lookup_expr='icontains',
        help_text='Filter by jingle name (case-insensitive)'
    )
    channel = django_filters.ModelChoiceFilter(
        field_name='playlist__channel',
        queryset=Channel.objects.filter(is_active=True),
        help_text='Filter by channel'
    )
    
    # Order and status filters
    order_min = django_filters.NumberFilter(
        field_name='order',
        lookup_expr='gte',
        help_text='Minimum order position'
    )
    order_max = django_filters.NumberFilter(
        field_name='order',
        lookup_expr='lte',
        help_text='Maximum order position'
    )
    is_active = django_filters.BooleanFilter(
        help_text='Filter by active status'
    )
    
    # Play count filters
    play_count_min = django_filters.NumberFilter(
        field_name='play_count',
        lookup_expr='gte',
        help_text='Minimum play count'
    )
    play_count_max = django_filters.NumberFilter(
        field_name='play_count',
        lookup_expr='lte',
        help_text='Maximum play count'
    )
    
    # Date filters
    start_date_after = django_filters.DateFilter(
        field_name='start_date',
        lookup_expr='gte',
        help_text='Start date after (YYYY-MM-DD)'
    )
    start_date_before = django_filters.DateFilter(
        field_name='start_date',
        lookup_expr='lte',
        help_text='Start date before (YYYY-MM-DD)'
    )
    end_date_after = django_filters.DateFilter(
        field_name='end_date',
        lookup_expr='gte',
        help_text='End date after (YYYY-MM-DD)'
    )
    end_date_before = django_filters.DateFilter(
        field_name='end_date',
        lookup_expr='lte',
        help_text='End date before (YYYY-MM-DD)'
    )
    
    # Custom filters
    available = django_filters.BooleanFilter(
        method='filter_available',
        help_text='Filter available playlist items'
    )
    
    class Meta:
        model = JinglePlaylistItem
        fields = {
            'id': ['exact', 'in'],
            'order': ['exact', 'lt', 'lte', 'gt', 'gte'],
            'is_active': ['exact'],
            'play_count': ['exact', 'lt', 'lte', 'gt', 'gte'],
            'created_at': ['exact', 'date', 'date__gte', 'date__lte'],
        }
    
    def filter_available(self, queryset, name, value):
        """Filter available playlist items."""
        if value:
            today = timezone.now().date()
            return queryset.filter(
                is_active=True,
                jingle__is_active=True,
                jingle__status='approved',
                jingle__is_deleted=False
            ).filter(
                Q(start_date__isnull=True) | Q(start_date__lte=today)
            ).filter(
                Q(end_date__isnull=True) | Q(end_date__gte=today)
            )
        return queryset


class JingleScheduleFilter(django_filters.FilterSet):
    """Filter for JingleSchedule model."""
    
    # Basic filters
    name = django_filters.CharFilter(
        field_name='name',
        lookup_expr='icontains',
        help_text='Filter by schedule name (case-insensitive)'
    )
    
    # Relationship filters
    channel = django_filters.ModelChoiceFilter(
        queryset=Channel.objects.filter(is_active=True),
        help_text='Filter by channel'
    )
    channel_name = django_filters.CharFilter(
        field_name='channel__name',
        lookup_expr='icontains',
        help_text='Filter by channel name (case-insensitive)'
    )
    playlist = django_filters.ModelChoiceFilter(
        queryset=JinglePlaylist.objects.filter(is_active=True),
        help_text='Filter by playlist'
    )
    playlist_name = django_filters.CharFilter(
        field_name='playlist__name',
        lookup_expr='icontains',
        help_text='Filter by playlist name (case-insensitive)'
    )
    
    # Type and status filters
    schedule_type = django_filters.ChoiceFilter(
        choices=JingleSchedule.SCHEDULE_TYPES,
        help_text='Filter by schedule type'
    )
    is_active = django_filters.BooleanFilter(
        help_text='Filter by active status'
    )
    
    # Priority filters
    priority = django_filters.NumberFilter(
        help_text='Filter by priority level'
    )
    priority_min = django_filters.NumberFilter(
        field_name='priority',
        lookup_expr='gte',
        help_text='Minimum priority level'
    )
    priority_max = django_filters.NumberFilter(
        field_name='priority',
        lookup_expr='lte',
        help_text='Maximum priority level'
    )
    
    # Time filters
    start_time_after = django_filters.TimeFilter(
        field_name='start_time',
        lookup_expr='gte',
        help_text='Start time after (HH:MM)'
    )
    start_time_before = django_filters.TimeFilter(
        field_name='start_time',
        lookup_expr='lte',
        help_text='Start time before (HH:MM)'
    )
    end_time_after = django_filters.TimeFilter(
        field_name='end_time',
        lookup_expr='gte',
        help_text='End time after (HH:MM)'
    )
    end_time_before = django_filters.TimeFilter(
        field_name='end_time',
        lookup_expr='lte',
        help_text='End time before (HH:MM)'
    )
    
    # Interval filters
    interval_min = django_filters.NumberFilter(
        field_name='interval_minutes',
        lookup_expr='gte',
        help_text='Minimum interval in minutes'
    )
    interval_max = django_filters.NumberFilter(
        field_name='interval_minutes',
        lookup_expr='lte',
        help_text='Maximum interval in minutes'
    )
    
    # Date filters
    start_date_after = django_filters.DateFilter(
        field_name='start_date',
        lookup_expr='gte',
        help_text='Start date after (YYYY-MM-DD)'
    )
    start_date_before = django_filters.DateFilter(
        field_name='start_date',
        lookup_expr='lte',
        help_text='Start date before (YYYY-MM-DD)'
    )
    end_date_after = django_filters.DateFilter(
        field_name='end_date',
        lookup_expr='gte',
        help_text='End date after (YYYY-MM-DD)'
    )
    end_date_before = django_filters.DateFilter(
        field_name='end_date',
        lookup_expr='lte',
        help_text='End date before (YYYY-MM-DD)'
    )
    
    created_after = django_filters.DateFilter(
        field_name='created_at',
        lookup_expr='gte',
        help_text='Created after date (YYYY-MM-DD)'
    )
    created_before = django_filters.DateFilter(
        field_name='created_at',
        lookup_expr='lte',
        help_text='Created before date (YYYY-MM-DD)'
    )
    
    # User filters
    created_by = django_filters.CharFilter(
        field_name='created_by__username',
        lookup_expr='icontains',
        help_text='Filter by creator username'
    )
    
    # Custom filters
    active_now = django_filters.BooleanFilter(
        method='filter_active_now',
        help_text='Filter schedules that are currently active'
    )
    has_time_range = django_filters.BooleanFilter(
        method='filter_has_time_range',
        help_text='Filter schedules with time range defined'
    )
    interval_based = django_filters.BooleanFilter(
        method='filter_interval_based',
        help_text='Filter interval-based schedules'
    )
    
    class Meta:
        model = JingleSchedule
        fields = {
            'id': ['exact', 'in'],
            'name': ['exact', 'icontains'],
            'schedule_type': ['exact', 'in'],
            'is_active': ['exact'],
            'priority': ['exact', 'lt', 'lte', 'gt', 'gte'],
            'interval_minutes': ['exact', 'lt', 'lte', 'gt', 'gte'],
            'created_at': ['exact', 'date', 'date__gte', 'date__lte'],
        }
    
    def filter_active_now(self, queryset, name, value):
        """Filter schedules that are currently active."""
        if value:
            active_schedules = []
            for schedule in queryset:
                if schedule.is_active_now():
                    active_schedules.append(schedule.id)
            return queryset.filter(id__in=active_schedules)
        return queryset
    
    def filter_has_time_range(self, queryset, name, value):
        """Filter schedules with time range defined."""
        if value:
            return queryset.filter(
                start_time__isnull=False,
                end_time__isnull=False
            )
        else:
            return queryset.filter(
                Q(start_time__isnull=True) | Q(end_time__isnull=True)
            )
    
    def filter_interval_based(self, queryset, name, value):
        """Filter interval-based schedules."""
        if value:
            return queryset.filter(
                schedule_type='interval',
                interval_minutes__isnull=False
            )
        else:
            return queryset.exclude(
                schedule_type='interval',
                interval_minutes__isnull=False
            )