# -*- coding: utf-8 -*-
"""
Campaigns Forms Module

This module contains all form classes for the campaigns app.
Includes model forms for creating and updating campaigns and related models.
"""

from django import forms
from django.utils.translation import gettext_lazy as _
from django.core.exceptions import ValidationError
from django.utils import timezone

from .models import Campaign, CampaignChannelSchedule, CampaignPerformance
from apps.advertisers.models import Brand
from apps.channels.models import TVChannel, GeographicZone
from apps.creatives.models import Creative


class CampaignForm(forms.ModelForm):
    """
    Form for creating and updating campaigns.
    """
    
    class Meta:
        model = Campaign
        fields = [
            'name', 'description', 'campaign_type', 'advertiser',
            'start_date', 'end_date', 'total_budget', 'daily_budget',
            'cost_per_spot', 'priority', 
            # 'target_audience',
            'geographic_zones', 'channels'
        ]
        widgets = {
            'name': forms.TextInput(attrs={
                'class': 'form-control',
                'placeholder': _('Enter campaign name')
            }),
            'description': forms.Textarea(attrs={
                'class': 'form-control',
                'rows': 4,
                'placeholder': _('Enter campaign description')
            }),
            'campaign_type': forms.Select(attrs={
                'class': 'form-control'
            }),
            'advertiser': forms.Select(attrs={
                'class': 'form-control'
            }),
            'start_date': forms.DateTimeInput(attrs={
                'class': 'form-control',
                'type': 'datetime-local'
            }),
            'end_date': forms.DateTimeInput(attrs={
                'class': 'form-control',
                'type': 'datetime-local'
            }),
            'total_budget': forms.NumberInput(attrs={
                'class': 'form-control',
                'step': '0.01',
                'min': '0'
            }),
            'daily_budget': forms.NumberInput(attrs={
                'class': 'form-control',
                'step': '0.01',
                'min': '0'
            }),
            'cost_per_spot': forms.NumberInput(attrs={
                'class': 'form-control',
                'step': '0.01',
                'min': '0'
            }),
            'priority': forms.NumberInput(attrs={
                'class': 'form-control',
                'min': '1',
                'max': '10'
            }),
            # 'target_audience': forms.Textarea(attrs={
            #     'class': 'form-control',
            #     'rows': 3,
            #     'placeholder': _('Describe target audience demographics')
            # }),
            'geographic_zones': forms.CheckboxSelectMultiple(attrs={
                'class': 'form-check-input'
            }),
            'channels': forms.CheckboxSelectMultiple(attrs={
                'class': 'form-check-input'
            })
        }
    
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        
        # Set queryset for foreign key fields
        self.fields['advertiser'].queryset = Brand.objects.filter(
            is_active=True
        ).order_by('name')
        
        self.fields['geographic_zones'].queryset = GeographicZone.objects.filter(
            is_active=True
        ).order_by('name')
        
        self.fields['channels'].queryset = TVChannel.objects.filter(
            is_active=True
        ).order_by('name')
        
        # Set required fields
        self.fields['name'].required = True
        self.fields['advertiser'].required = True
        self.fields['start_date'].required = True
        self.fields['end_date'].required = True
        self.fields['total_budget'].required = True
        
        # Add help text
        self.fields['priority'].help_text = _('Priority level from 1 (lowest) to 10 (highest)')
        self.fields['daily_budget'].help_text = _('Leave empty to distribute total budget evenly')
        self.fields['cost_per_spot'].help_text = _('Cost per advertising spot')
    
    def clean(self):
        cleaned_data = super().clean()
        start_date = cleaned_data.get('start_date')
        end_date = cleaned_data.get('end_date')
        total_budget = cleaned_data.get('total_budget')
        daily_budget = cleaned_data.get('daily_budget')
        
        # Validate date range
        if start_date and end_date:
            if start_date >= end_date:
                raise ValidationError(_('End date must be after start date.'))
            
            if start_date < timezone.now():
                raise ValidationError(_('Start date cannot be in the past.'))
        
        # Validate budget
        if total_budget and daily_budget:
            if start_date and end_date:
                campaign_days = (end_date.date() - start_date.date()).days + 1
                if daily_budget * campaign_days > total_budget:
                    raise ValidationError(
                        _('Daily budget × campaign days cannot exceed total budget.')
                    )
        
        return cleaned_data
    
    def clean_name(self):
        name = self.cleaned_data.get('name')
        if name:
            # Check for duplicate names (excluding current instance if updating)
            queryset = Campaign.objects.filter(name__iexact=name)
            if self.instance.pk:
                queryset = queryset.exclude(pk=self.instance.pk)
            
            if queryset.exists():
                raise ValidationError(_('A campaign with this name already exists.'))
        
        return name


class CampaignChannelScheduleForm(forms.ModelForm):
    """
    Form for creating and updating campaign channel schedules.
    """
    
    class Meta:
        model = CampaignChannelSchedule
        fields = [
            'campaign', 'channel', 'start_time', 'end_time',
            'days_of_week', 'spots_per_day', 'channel_budget'
        ]
        widgets = {
            'campaign': forms.Select(attrs={
                'class': 'form-control'
            }),
            'channel': forms.Select(attrs={
                'class': 'form-control'
            }),
            'start_time': forms.TimeInput(attrs={
                'class': 'form-control',
                'type': 'time'
            }),
            'end_time': forms.TimeInput(attrs={
                'class': 'form-control',
                'type': 'time'
            }),
            'days_of_week': forms.TextInput(attrs={
                'class': 'form-control',
                'placeholder': _('e.g., 1,2,3,4,5 for weekdays')
            }),
            'spots_per_day': forms.NumberInput(attrs={
                'class': 'form-control',
                'min': '1'
            }),
            'channel_budget': forms.NumberInput(attrs={
                'class': 'form-control',
                'step': '0.01',
                'min': '0'
            })
        }
    
    def __init__(self, *args, **kwargs):
        campaign = kwargs.pop('campaign', None)
        super().__init__(*args, **kwargs)
        
        if campaign:
            self.fields['campaign'].initial = campaign
            self.fields['campaign'].widget = forms.HiddenInput()
            
            # Filter channels to only those associated with the campaign
            self.fields['channel'].queryset = campaign.channels.filter(
                is_active=True
            ).order_by('name')
        else:
            self.fields['channel'].queryset = TVChannel.objects.filter(
                is_active=True
            ).order_by('name')
        
        # Add help text
        self.fields['days_of_week'].help_text = _(
            'Comma-separated list of weekdays (1=Monday, 7=Sunday)'
        )
        self.fields['spots_per_day'].help_text = _('Number of spots to air per day')
    
    def clean_days_of_week(self):
        days_of_week = self.cleaned_data.get('days_of_week')
        if days_of_week:
            try:
                days = [int(day.strip()) for day in days_of_week.split(',')]
                for day in days:
                    if day < 1 or day > 7:
                        raise ValueError()
                return ','.join(map(str, sorted(set(days))))
            except (ValueError, AttributeError):
                raise ValidationError(
                    _('Please enter valid weekday numbers (1-7) separated by commas.')
                )
        return days_of_week
    
    def clean(self):
        cleaned_data = super().clean()
        start_time = cleaned_data.get('start_time')
        end_time = cleaned_data.get('end_time')
        
        if start_time and end_time:
            if start_time >= end_time:
                raise ValidationError(_('End time must be after start time.'))
        
        return cleaned_data


class CampaignPerformanceForm(forms.ModelForm):
    """
    Form for manually entering campaign performance data.
    """
    
    class Meta:
        model = CampaignPerformance
        fields = [
            'campaign', 'date', 'impressions', 'spots_aired',
            'spend', 'reach', 'frequency'
        ]
        widgets = {
            'campaign': forms.Select(attrs={
                'class': 'form-control'
            }),
            'date': forms.DateInput(attrs={
                'class': 'form-control',
                'type': 'date'
            }),
            'impressions': forms.NumberInput(attrs={
                'class': 'form-control',
                'min': '0'
            }),
            'spots_aired': forms.NumberInput(attrs={
                'class': 'form-control',
                'min': '0'
            }),
            'spend': forms.NumberInput(attrs={
                'class': 'form-control',
                'step': '0.01',
                'min': '0'
            }),
            'reach': forms.NumberInput(attrs={
                'class': 'form-control',
                'min': '0'
            }),
            'frequency': forms.NumberInput(attrs={
                'class': 'form-control',
                'step': '0.01',
                'min': '0'
            })
        }
    
    def __init__(self, *args, **kwargs):
        campaign = kwargs.pop('campaign', None)
        super().__init__(*args, **kwargs)
        
        if campaign:
            self.fields['campaign'].initial = campaign
            self.fields['campaign'].widget = forms.HiddenInput()
        
        # Set default date to today
        if not self.instance.pk:
            self.fields['date'].initial = timezone.now().date()
    
    def clean_date(self):
        date = self.cleaned_data.get('date')
        campaign = self.cleaned_data.get('campaign')
        
        if date and campaign:
            # Check if performance data already exists for this date
            queryset = CampaignPerformance.objects.filter(
                campaign=campaign,
                date=date
            )
            if self.instance.pk:
                queryset = queryset.exclude(pk=self.instance.pk)
            
            if queryset.exists():
                raise ValidationError(
                    _('Performance data for this date already exists.')
                )
            
            # Check if date is within campaign period
            if date < campaign.start_date.date():
                raise ValidationError(
                    _('Date cannot be before campaign start date.')
                )
            
            if campaign.end_date and date > campaign.end_date.date():
                raise ValidationError(
                    _('Date cannot be after campaign end date.')
                )
        
        return date


class CampaignFilterForm(forms.Form):
    """
    Form for filtering campaigns in list view.
    """
    
    STATUS_CHOICES = [('', _('All Statuses'))] + Campaign.CAMPAIGN_STATUS
    TYPE_CHOICES = [('', _('All Types'))] + Campaign.CAMPAIGN_TYPES
    
    search = forms.CharField(
        required=False,
        widget=forms.TextInput(attrs={
            'class': 'form-control',
            'placeholder': _('Search campaigns...')
        })
    )
    
    status = forms.ChoiceField(
        choices=STATUS_CHOICES,
        required=False,
        widget=forms.Select(attrs={
            'class': 'form-control'
        })
    )
    
    campaign_type = forms.ChoiceField(
        choices=TYPE_CHOICES,
        required=False,
        widget=forms.Select(attrs={
            'class': 'form-control'
        })
    )
    
    advertiser = forms.ModelChoiceField(
        queryset=Brand.objects.filter(is_active=True).order_by('name'),
        required=False,
        empty_label=_('All Advertisers'),
        widget=forms.Select(attrs={
            'class': 'form-control'
        })
    )
    
    start_date_from = forms.DateField(
        required=False,
        widget=forms.DateInput(attrs={
            'class': 'form-control',
            'type': 'date'
        })
    )
    
    start_date_to = forms.DateField(
        required=False,
        widget=forms.DateInput(attrs={
            'class': 'form-control',
            'type': 'date'
        })
    )


class BulkCampaignActionForm(forms.Form):
    """
    Form for bulk actions on campaigns.
    """
    
    ACTION_CHOICES = [
        ('activate', _('Activate')),
        ('pause', _('Pause')),
        ('complete', _('Mark as Completed')),
        ('delete', _('Delete'))
    ]
    
    action = forms.ChoiceField(
        choices=ACTION_CHOICES,
        widget=forms.Select(attrs={
            'class': 'form-control'
        })
    )
    
    campaign_ids = forms.CharField(
        widget=forms.HiddenInput()
    )
    
    def clean_campaign_ids(self):
        campaign_ids = self.cleaned_data.get('campaign_ids')
        if campaign_ids:
            try:
                ids = [int(id.strip()) for id in campaign_ids.split(',')]
                return ids
            except (ValueError, AttributeError):
                raise ValidationError(_('Invalid campaign IDs.'))
        return []