# -*- coding: utf-8 -*-
"""
Advertisers App Filters

This module contains filter classes for the Advertisers application.
It provides comprehensive filtering capabilities for all models using
django-filter for advanced search and filtering functionality.
"""

from decimal import Decimal
from django.db.models import Q
from django.utils.translation import gettext_lazy as _
from django_filters import rest_framework as filters
from django_filters.widgets import BooleanWidget

from .models import (
    BrandCategory,
    Agency,
    Advertiser,
    Brand,
    AdvertiserContact,
    AgencyUser,
    AdvertiserBilling
)


class BrandCategoryFilter(filters.FilterSet):
    """
    Filter class for brand categories with hierarchical and status filtering.
    """
    
    # Text search across name and description
    search = filters.CharFilter(
        method='filter_search',
        label=_('Search'),
        help_text=_('Search in name and description')
    )
    
    # Parent category filtering
    parent = filters.ModelChoiceFilter(
        queryset=BrandCategory.objects.filter(is_active=True),
        label=_('Parent Category'),
        help_text=_('Filter by parent category')
    )
    
    # Root categories (no parent)
    is_root = filters.BooleanFilter(
        field_name='parent',
        lookup_expr='isnull',
        widget=BooleanWidget(),
        label=_('Root Categories'),
        help_text=_('Show only root categories (no parent)')
    )
    
    # Categories with brands
    has_brands = filters.BooleanFilter(
        method='filter_has_brands',
        widget=BooleanWidget(),
        label=_('Has Brands'),
        help_text=_('Show only categories with brands')
    )
    
    # Status filtering
    is_active = filters.BooleanFilter(
        widget=BooleanWidget(),
        label=_('Active'),
        help_text=_('Filter by active status')
    )
    
    # Order range filtering
    order_min = filters.NumberFilter(
        field_name='order',
        lookup_expr='gte',
        label=_('Minimum Order'),
        help_text=_('Minimum display order')
    )
    
    order_max = filters.NumberFilter(
        field_name='order',
        lookup_expr='lte',
        label=_('Maximum Order'),
        help_text=_('Maximum display order')
    )
    
    # Date range filtering
    created_after = filters.DateTimeFilter(
        field_name='created_at',
        lookup_expr='gte',
        label=_('Created After'),
        help_text=_('Show categories created after this date')
    )
    
    created_before = filters.DateTimeFilter(
        field_name='created_at',
        lookup_expr='lte',
        label=_('Created Before'),
        help_text=_('Show categories created before this date')
    )
    
    class Meta:
        model = BrandCategory
        fields = {
            'name': ['exact', 'icontains', 'istartswith'],
            'description': ['icontains'],
            'order': ['exact', 'lt', 'gt'],
            'is_active': ['exact'],
            'created_at': ['exact', 'date', 'year', 'month'],
            'updated_at': ['exact', 'date']
        }
    
    def filter_search(self, queryset, name, value):
        """
        Filter by search term across multiple fields.
        """
        if value:
            return queryset.filter(
                Q(name__icontains=value) |
                Q(description__icontains=value)
            )
        return queryset
    
    def filter_has_brands(self, queryset, name, value):
        """
        Filter categories that have brands.
        """
        if value is True:
            return queryset.filter(brands__isnull=False).distinct()
        elif value is False:
            return queryset.filter(brands__isnull=True)
        return queryset


class AgencyFilter(filters.FilterSet):
    """
    Filter class for agencies with comprehensive filtering options.
    """
    
    # Text search across multiple fields
    search = filters.CharFilter(
        method='filter_search',
        label=_('Search'),
        help_text=_('Search in name, code, email, and city')
    )
    
    # Location filtering
    country = filters.CharFilter(
        lookup_expr='icontains',
        label=_('Country'),
        help_text=_('Filter by country')
    )
    
    city = filters.CharFilter(
        lookup_expr='icontains',
        label=_('City'),
        help_text=_('Filter by city')
    )
    
    # Commission rate filtering
    commission_rate_min = filters.NumberFilter(
        field_name='commission_rate',
        lookup_expr='gte',
        label=_('Minimum Commission Rate'),
        help_text=_('Minimum commission rate percentage')
    )
    
    commission_rate_max = filters.NumberFilter(
        field_name='commission_rate',
        lookup_expr='lte',
        label=_('Maximum Commission Rate'),
        help_text=_('Maximum commission rate percentage')
    )
    
    # Advertiser count filtering
    has_advertisers = filters.BooleanFilter(
        method='filter_has_advertisers',
        widget=BooleanWidget(),
        label=_('Has Advertisers'),
        help_text=_('Show only agencies with advertisers')
    )
    
    min_advertisers = filters.NumberFilter(
        method='filter_min_advertisers',
        label=_('Minimum Advertisers'),
        help_text=_('Minimum number of advertisers')
    )
    
    # Status filtering
    is_active = filters.BooleanFilter(
        widget=BooleanWidget(),
        label=_('Active'),
        help_text=_('Filter by active status')
    )
    
    # Date range filtering
    created_after = filters.DateTimeFilter(
        field_name='created_at',
        lookup_expr='gte',
        label=_('Created After'),
        help_text=_('Show agencies created after this date')
    )
    
    created_before = filters.DateTimeFilter(
        field_name='created_at',
        lookup_expr='lte',
        label=_('Created Before'),
        help_text=_('Show agencies created before this date')
    )
    
    class Meta:
        model = Agency
        fields = {
            'name': ['exact', 'icontains', 'istartswith'],
            'code': ['exact', 'icontains'],
            'email': ['exact', 'icontains'],
            'commission_rate': ['exact', 'lt', 'gt'],
            'is_active': ['exact'],
            'created_at': ['exact', 'date', 'year', 'month'],
            'updated_at': ['exact', 'date']
        }
    
    def filter_search(self, queryset, name, value):
        """
        Filter by search term across multiple fields.
        """
        if value:
            return queryset.filter(
                Q(name__icontains=value) |
                Q(code__icontains=value) |
                Q(email__icontains=value) |
                Q(city__icontains=value) |
                Q(description__icontains=value)
            )
        return queryset
    
    def filter_has_advertisers(self, queryset, name, value):
        """
        Filter agencies that have advertisers.
        """
        if value is True:
            return queryset.filter(advertisers__isnull=False).distinct()
        elif value is False:
            return queryset.filter(advertisers__isnull=True)
        return queryset
    
    def filter_min_advertisers(self, queryset, name, value):
        """
        Filter agencies with minimum number of advertisers.
        """
        if value is not None:
            from django.db.models import Count
            return queryset.annotate(
                advertiser_count=Count('advertisers')
            ).filter(advertiser_count__gte=value)
        return queryset


class AdvertiserFilter(filters.FilterSet):
    """
    Filter class for advertisers with type, agency, and financial filtering.
    """
    
    # Text search across multiple fields
    search = filters.CharFilter(
        method='filter_search',
        label=_('Search'),
        help_text=_('Search in name, code, email, and industry')
    )
    
    # Advertiser type filtering
    advertiser_type = filters.ChoiceFilter(
        choices=Advertiser.ADVERTISER_TYPES,
        label=_('Advertiser Type'),
        help_text=_('Filter by advertiser type')
    )
    
    # Agency filtering
    agency = filters.ModelChoiceFilter(
        queryset=Agency.objects.filter(is_active=True),
        label=_('Agency'),
        help_text=_('Filter by managing agency')
    )
    
    # Agency-managed filtering
    is_agency_managed = filters.BooleanFilter(
        method='filter_agency_managed',
        widget=BooleanWidget(),
        label=_('Agency Managed'),
        help_text=_('Show only agency-managed advertisers')
    )
    
    # Location filtering
    country = filters.CharFilter(
        lookup_expr='icontains',
        label=_('Country'),
        help_text=_('Filter by country')
    )
    
    city = filters.CharFilter(
        lookup_expr='icontains',
        label=_('City'),
        help_text=_('Filter by city')
    )
    
    # Industry filtering
    industry = filters.CharFilter(
        lookup_expr='icontains',
        label=_('Industry'),
        help_text=_('Filter by industry')
    )
    
    # Credit limit filtering
    credit_limit_min = filters.NumberFilter(
        field_name='credit_limit',
        lookup_expr='gte',
        label=_('Minimum Credit Limit'),
        help_text=_('Minimum credit limit amount')
    )
    
    credit_limit_max = filters.NumberFilter(
        field_name='credit_limit',
        lookup_expr='lte',
        label=_('Maximum Credit Limit'),
        help_text=_('Maximum credit limit amount')
    )
    
    # Brand count filtering
    has_brands = filters.BooleanFilter(
        method='filter_has_brands',
        widget=BooleanWidget(),
        label=_('Has Brands'),
        help_text=_('Show only advertisers with brands')
    )
    
    min_brands = filters.NumberFilter(
        method='filter_min_brands',
        label=_('Minimum Brands'),
        help_text=_('Minimum number of brands')
    )
    
    # Status filtering
    is_active = filters.BooleanFilter(
        widget=BooleanWidget(),
        label=_('Active'),
        help_text=_('Filter by active status')
    )
    
    # Date range filtering
    created_after = filters.DateTimeFilter(
        field_name='created_at',
        lookup_expr='gte',
        label=_('Created After'),
        help_text=_('Show advertisers created after this date')
    )
    
    created_before = filters.DateTimeFilter(
        field_name='created_at',
        lookup_expr='lte',
        label=_('Created Before'),
        help_text=_('Show advertisers created before this date')
    )
    
    class Meta:
        model = Advertiser
        fields = {
            'name': ['exact', 'icontains', 'istartswith'],
            'code': ['exact', 'icontains'],
            'email': ['exact', 'icontains'],
            'advertiser_type': ['exact'],
            'industry': ['exact', 'icontains'],
            'credit_limit': ['exact', 'lt', 'gt'],
            'is_active': ['exact'],
            'created_at': ['exact', 'date', 'year', 'month'],
            'updated_at': ['exact', 'date']
        }
    
    def filter_search(self, queryset, name, value):
        """
        Filter by search term across multiple fields.
        """
        if value:
            return queryset.filter(
                Q(name__icontains=value) |
                Q(code__icontains=value) |
                Q(email__icontains=value) |
                Q(industry__icontains=value) |
                Q(description__icontains=value)
            )
        return queryset
    
    def filter_agency_managed(self, queryset, name, value):
        """
        Filter agency-managed advertisers.
        """
        if value is True:
            return queryset.filter(
                advertiser_type='agency_managed',
                agency__isnull=False
            )
        elif value is False:
            return queryset.filter(
                Q(advertiser_type__ne='agency_managed') |
                Q(agency__isnull=True)
            )
        return queryset
    
    def filter_has_brands(self, queryset, name, value):
        """
        Filter advertisers that have brands.
        """
        if value is True:
            return queryset.filter(brands__isnull=False).distinct()
        elif value is False:
            return queryset.filter(brands__isnull=True)
        return queryset
    
    def filter_min_brands(self, queryset, name, value):
        """
        Filter advertisers with minimum number of brands.
        """
        if value is not None:
            from django.db.models import Count
            return queryset.annotate(
                brand_count=Count('brands')
            ).filter(brand_count__gte=value)
        return queryset


class BrandFilter(filters.FilterSet):
    """
    Filter class for brands with category, advertiser, and campaign filtering.
    """
    
    # Text search across multiple fields
    search = filters.CharFilter(
        method='filter_search',
        label=_('Search'),
        help_text=_('Search in name, code, and description')
    )
    
    # Advertiser filtering
    advertiser = filters.ModelChoiceFilter(
        queryset=Advertiser.objects.filter(is_active=True),
        label=_('Advertiser'),
        help_text=_('Filter by advertiser')
    )
    
    # Agency filtering (through advertiser)
    agency = filters.ModelChoiceFilter(
        field_name='advertiser__agency',
        queryset=Agency.objects.filter(is_active=True),
        label=_('Agency'),
        help_text=_('Filter by agency')
    )
    
    # Category filtering
    category = filters.ModelChoiceFilter(
        queryset=BrandCategory.objects.filter(is_active=True),
        label=_('Category'),
        help_text=_('Filter by brand category')
    )
    
    # Category hierarchy filtering
    category_parent = filters.ModelChoiceFilter(
        field_name='category__parent',
        queryset=BrandCategory.objects.filter(is_active=True, parent__isnull=True),
        label=_('Category Parent'),
        help_text=_('Filter by parent category')
    )
    
    # Uncategorized brands
    is_uncategorized = filters.BooleanFilter(
        field_name='category',
        lookup_expr='isnull',
        widget=BooleanWidget(),
        label=_('Uncategorized'),
        help_text=_('Show only uncategorized brands')
    )
    
    # Color filtering
    has_colors = filters.BooleanFilter(
        method='filter_has_colors',
        widget=BooleanWidget(),
        label=_('Has Colors'),
        help_text=_('Show only brands with color information')
    )
    
    # Logo filtering
    has_logo = filters.BooleanFilter(
        field_name='logo',
        lookup_expr='isnull',
        exclude=True,
        widget=BooleanWidget(),
        label=_('Has Logo'),
        help_text=_('Show only brands with logos')
    )
    
    # Campaign filtering
    has_campaigns = filters.BooleanFilter(
        method='filter_has_campaigns',
        widget=BooleanWidget(),
        label=_('Has Campaigns'),
        help_text=_('Show only brands with campaigns')
    )
    
    # Status filtering
    is_active = filters.BooleanFilter(
        widget=BooleanWidget(),
        label=_('Active'),
        help_text=_('Filter by active status')
    )
    
    # Date range filtering
    created_after = filters.DateTimeFilter(
        field_name='created_at',
        lookup_expr='gte',
        label=_('Created After'),
        help_text=_('Show brands created after this date')
    )
    
    created_before = filters.DateTimeFilter(
        field_name='created_at',
        lookup_expr='lte',
        label=_('Created Before'),
        help_text=_('Show brands created before this date')
    )
    
    class Meta:
        model = Brand
        fields = {
            'name': ['exact', 'icontains', 'istartswith'],
            'code': ['exact', 'icontains'],
            'description': ['icontains'],
            'website': ['exact', 'icontains'],
            'primary_color': ['exact'],
            'secondary_color': ['exact'],
            'is_active': ['exact'],
            'created_at': ['exact', 'date', 'year', 'month'],
            'updated_at': ['exact', 'date']
        }
    
    def filter_search(self, queryset, name, value):
        """
        Filter by search term across multiple fields.
        """
        if value:
            return queryset.filter(
                Q(name__icontains=value) |
                Q(code__icontains=value) |
                Q(description__icontains=value) |
                Q(advertiser__name__icontains=value)
            )
        return queryset
    
    def filter_has_colors(self, queryset, name, value):
        """
        Filter brands that have color information.
        """
        if value is True:
            return queryset.filter(
                Q(primary_color__isnull=False) |
                Q(secondary_color__isnull=False)
            ).exclude(
                Q(primary_color='') & Q(secondary_color='')
            )
        elif value is False:
            return queryset.filter(
                Q(primary_color__isnull=True) | Q(primary_color=''),
                Q(secondary_color__isnull=True) | Q(secondary_color='')
            )
        return queryset
    
    def filter_has_campaigns(self, queryset, name, value):
        """
        Filter brands that have campaigns.
        """
        try:
            from apps.campaigns.models import Campaign
            if value is True:
                return queryset.filter(
                    id__in=Campaign.objects.values_list('brand_id', flat=True)
                ).distinct()
            elif value is False:
                return queryset.exclude(
                    id__in=Campaign.objects.values_list('brand_id', flat=True)
                )
        except ImportError:
            pass
        return queryset


class AdvertiserContactFilter(filters.FilterSet):
    """
    Filter class for advertiser contacts with type and status filtering.
    """
    
    # Text search across multiple fields
    search = filters.CharFilter(
        method='filter_search',
        label=_('Search'),
        help_text=_('Search in name, email, and title')
    )
    
    # Advertiser filtering
    advertiser = filters.ModelChoiceFilter(
        queryset=Advertiser.objects.filter(is_active=True),
        label=_('Advertiser'),
        help_text=_('Filter by advertiser')
    )
    
    # Contact type filtering
    contact_type = filters.ChoiceFilter(
        choices=AdvertiserContact.CONTACT_TYPES,
        label=_('Contact Type'),
        help_text=_('Filter by contact type')
    )
    
    # Status filtering
    is_active = filters.BooleanFilter(
        widget=BooleanWidget(),
        label=_('Active'),
        help_text=_('Filter by active status')
    )
    
    # Date range filtering
    created_after = filters.DateTimeFilter(
        field_name='created_at',
        lookup_expr='gte',
        label=_('Created After'),
        help_text=_('Show contacts created after this date')
    )
    
    created_before = filters.DateTimeFilter(
        field_name='created_at',
        lookup_expr='lte',
        label=_('Created Before'),
        help_text=_('Show contacts created before this date')
    )
    
    class Meta:
        model = AdvertiserContact
        fields = {
            'first_name': ['exact', 'icontains', 'istartswith'],
            'last_name': ['exact', 'icontains', 'istartswith'],
            'email': ['exact', 'icontains'],
            'title': ['exact', 'icontains'],
            'contact_type': ['exact'],
            'is_active': ['exact'],
            'created_at': ['exact', 'date', 'year', 'month'],
            'updated_at': ['exact', 'date']
        }
    
    def filter_search(self, queryset, name, value):
        """
        Filter by search term across multiple fields.
        """
        if value:
            return queryset.filter(
                Q(first_name__icontains=value) |
                Q(last_name__icontains=value) |
                Q(email__icontains=value) |
                Q(title__icontains=value) |
                Q(advertiser__name__icontains=value)
            )
        return queryset


class AgencyUserFilter(filters.FilterSet):
    """
    Filter class for agency users with role and permission filtering.
    """
    
    # Text search across multiple fields
    search = filters.CharFilter(
        method='filter_search',
        label=_('Search'),
        help_text=_('Search in user name, email, and agency name')
    )
    
    # Agency filtering
    agency = filters.ModelChoiceFilter(
        queryset=Agency.objects.filter(is_active=True),
        label=_('Agency'),
        help_text=_('Filter by agency')
    )
    
    # Role filtering
    role = filters.ChoiceFilter(
        choices=AgencyUser.AGENCY_ROLES,
        label=_('Role'),
        help_text=_('Filter by user role')
    )
    
    # Permission filtering
    can_create_campaigns = filters.BooleanFilter(
        widget=BooleanWidget(),
        label=_('Can Create Campaigns'),
        help_text=_('Filter by campaign creation permission')
    )
    
    can_manage_advertisers = filters.BooleanFilter(
        widget=BooleanWidget(),
        label=_('Can Manage Advertisers'),
        help_text=_('Filter by advertiser management permission')
    )
    
    can_view_reports = filters.BooleanFilter(
        widget=BooleanWidget(),
        label=_('Can View Reports'),
        help_text=_('Filter by report viewing permission')
    )
    
    can_manage_billing = filters.BooleanFilter(
        widget=BooleanWidget(),
        label=_('Can Manage Billing'),
        help_text=_('Filter by billing management permission')
    )
    
    # Status filtering
    is_active = filters.BooleanFilter(
        widget=BooleanWidget(),
        label=_('Active'),
        help_text=_('Filter by active status')
    )
    
    # Date range filtering
    joined_after = filters.DateTimeFilter(
        field_name='joined_at',
        lookup_expr='gte',
        label=_('Joined After'),
        help_text=_('Show users who joined after this date')
    )
    
    joined_before = filters.DateTimeFilter(
        field_name='joined_at',
        lookup_expr='lte',
        label=_('Joined Before'),
        help_text=_('Show users who joined before this date')
    )
    
    class Meta:
        model = AgencyUser
        fields = {
            'role': ['exact'],
            'can_create_campaigns': ['exact'],
            'can_manage_advertisers': ['exact'],
            'can_view_reports': ['exact'],
            'can_manage_billing': ['exact'],
            'is_active': ['exact'],
            'joined_at': ['exact', 'date', 'year', 'month'],
            'created_at': ['exact', 'date', 'year', 'month'],
            'updated_at': ['exact', 'date']
        }
    
    def filter_search(self, queryset, name, value):
        """
        Filter by search term across multiple fields.
        """
        if value:
            return queryset.filter(
                Q(user__first_name__icontains=value) |
                Q(user__last_name__icontains=value) |
                Q(user__email__icontains=value) |
                Q(agency__name__icontains=value)
            )
        return queryset


class AdvertiserBillingFilter(filters.FilterSet):
    """
    Filter class for advertiser billing with financial and status filtering.
    """
    
    # Text search across multiple fields
    search = filters.CharFilter(
        method='filter_search',
        label=_('Search'),
        help_text=_('Search in advertiser name, billing name, and tax ID')
    )
    
    # Advertiser filtering
    advertiser = filters.ModelChoiceFilter(
        queryset=Advertiser.objects.filter(is_active=True),
        label=_('Advertiser'),
        help_text=_('Filter by advertiser')
    )
    
    # Payment method filtering
    payment_method = filters.ChoiceFilter(
        choices=AdvertiserBilling.PAYMENT_METHODS,
        label=_('Payment Method'),
        help_text=_('Filter by payment method')
    )
    
    # Billing cycle filtering
    billing_cycle = filters.ChoiceFilter(
        choices=AdvertiserBilling.BILLING_CYCLES,
        label=_('Billing Cycle'),
        help_text=_('Filter by billing cycle')
    )
    
    # Credit limit filtering
    credit_limit_min = filters.NumberFilter(
        field_name='credit_limit',
        lookup_expr='gte',
        label=_('Minimum Credit Limit'),
        help_text=_('Minimum credit limit amount')
    )
    
    credit_limit_max = filters.NumberFilter(
        field_name='credit_limit',
        lookup_expr='lte',
        label=_('Maximum Credit Limit'),
        help_text=_('Maximum credit limit amount')
    )
    
    # Balance filtering
    balance_min = filters.NumberFilter(
        field_name='current_balance',
        lookup_expr='gte',
        label=_('Minimum Balance'),
        help_text=_('Minimum current balance')
    )
    
    balance_max = filters.NumberFilter(
        field_name='current_balance',
        lookup_expr='lte',
        label=_('Maximum Balance'),
        help_text=_('Maximum current balance')
    )
    
    # Over limit filtering
    is_over_limit = filters.BooleanFilter(
        method='filter_over_limit',
        widget=BooleanWidget(),
        label=_('Over Credit Limit'),
        help_text=_('Show advertisers over their credit limit')
    )
    
    # Low credit filtering
    is_low_credit = filters.BooleanFilter(
        method='filter_low_credit',
        widget=BooleanWidget(),
        label=_('Low Credit'),
        help_text=_('Show advertisers with low available credit')
    )
    
    # Status filtering
    is_active = filters.BooleanFilter(
        widget=BooleanWidget(),
        label=_('Active'),
        help_text=_('Filter by active status')
    )
    
    class Meta:
        model = AdvertiserBilling
        fields = {
            'billing_name': ['exact', 'icontains'],
            'tax_id': ['exact', 'icontains'],
            'payment_method': ['exact'],
            'billing_cycle': ['exact'],
            'credit_limit': ['exact', 'lt', 'gt'],
            'current_balance': ['exact', 'lt', 'gt'],
            'is_active': ['exact'],
            'created_at': ['exact', 'date', 'year', 'month'],
            'updated_at': ['exact', 'date']
        }
    
    def filter_search(self, queryset, name, value):
        """
        Filter by search term across multiple fields.
        """
        if value:
            return queryset.filter(
                Q(advertiser__name__icontains=value) |
                Q(billing_name__icontains=value) |
                Q(tax_id__icontains=value)
            )
        return queryset
    
    def filter_over_limit(self, queryset, name, value):
        """
        Filter advertisers over their credit limit.
        """
        from django.db.models import F
        if value is True:
            return queryset.filter(current_balance__gt=F('credit_limit'))
        elif value is False:
            return queryset.filter(current_balance__lte=F('credit_limit'))
        return queryset
    
    def filter_low_credit(self, queryset, name, value):
        """
        Filter advertisers with low available credit (less than 10% of limit).
        """
        from django.db.models import F
        if value is True:
            return queryset.filter(current_balance__gt=F('credit_limit') * Decimal('0.9'))
        elif value is False:
            return queryset.filter(current_balance__lte=F('credit_limit') * Decimal('0.9'))
        return queryset