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

This module contains all serializer classes for the campaigns app.
Includes serializers for REST API endpoints and data export.
"""

from rest_framework import serializers
from django.utils.translation import gettext_lazy as _

from .models import Campaign, CampaignChannelSchedule, CampaignPerformance
from apps.advertisers.serializers import BrandSerializer
from apps.channels.serializers import TVChannelListSerializer, GeographicZoneSerializer


class CampaignChannelScheduleSerializer(serializers.ModelSerializer):
    """
    Serializer for campaign channel schedules.
    """
    channel = TVChannelListSerializer(read_only=True)
    channel_id = serializers.IntegerField(write_only=True)
    
    class Meta:
        model = CampaignChannelSchedule
        fields = [
            'id', 'channel', 'channel_id', 'start_time', 'end_time',
            'days_of_week', 'spots_per_day', 'channel_budget',
            'impressions_delivered', 'amount_spent', 'created_at', 'updated_at'
        ]
        read_only_fields = ['id', 'impressions_delivered', 'amount_spent', 'created_at', 'updated_at']
    
    def validate_days_of_week(self, value):
        """
        Validate days of week format.
        """
        if value:
            try:
                days = [int(day.strip()) for day in value.split(',')]
                for day in days:
                    if day < 1 or day > 7:
                        raise ValueError()
                return ','.join(map(str, sorted(set(days))))
            except (ValueError, AttributeError):
                raise serializers.ValidationError(
                    _('Please enter valid weekday numbers (1-7) separated by commas.')
                )
        return value
    
    def validate(self, data):
        """
        Validate schedule data.
        """
        start_time = data.get('start_time')
        end_time = data.get('end_time')
        
        if start_time and end_time and start_time >= end_time:
            raise serializers.ValidationError({
                'end_time': _('End time must be after start time.')
            })
        
        return data


class CampaignPerformanceSerializer(serializers.ModelSerializer):
    """
    Serializer for campaign performance data.
    """
    cpm = serializers.DecimalField(max_digits=10, decimal_places=2, read_only=True)
    
    class Meta:
        model = CampaignPerformance
        fields = [
            'id', 'date', 'impressions', 'spots_aired', 'spend',
            'cpm', 'reach', 'frequency', 'created_at', 'updated_at'
        ]
        read_only_fields = ['id', 'cpm', 'created_at', 'updated_at']
    
    def validate_date(self, value):
        """
        Validate performance date.
        """
        campaign = self.context.get('campaign')
        if campaign and value:
            if value < campaign.start_date.date():
                raise serializers.ValidationError(
                    _('Date cannot be before campaign start date.')
                )
            
            if campaign.end_date and value > campaign.end_date.date():
                raise serializers.ValidationError(
                    _('Date cannot be after campaign end date.')
                )
        
        return value


class CampaignListSerializer(serializers.ModelSerializer):
    """
    Serializer for campaign list view (minimal data).
    """
    advertiser = BrandSerializer(read_only=True)
    status_display = serializers.CharField(source='get_status_display', read_only=True)
    type_display = serializers.CharField(source='get_campaign_type_display', read_only=True)
    budget_utilization = serializers.SerializerMethodField()
    days_remaining = serializers.SerializerMethodField()
    is_active = serializers.SerializerMethodField()
    
    class Meta:
        model = Campaign
        fields = [
            'id', 'name', 'description', 'campaign_type', 'type_display',
            'advertiser', 'status', 'status_display', 'start_date', 'end_date',
            'total_budget', 'total_spend', 'budget_utilization',
            'total_impressions', 'priority', 'days_remaining', 'is_active',
            'created_at', 'updated_at'
        ]
    
    def get_budget_utilization(self, obj):
        return obj.budget_utilization()
    
    def get_days_remaining(self, obj):
        return obj.days_remaining()
    
    def get_is_active(self, obj):
        return obj.is_active()


class CampaignDetailSerializer(serializers.ModelSerializer):
    """
    Serializer for campaign detail view (full data).
    """
    advertiser = BrandSerializer(read_only=True)
    geographic_zones = GeographicZoneSerializer(many=True, read_only=True)
    channels = TVChannelListSerializer(many=True, read_only=True)
    channel_schedules = CampaignChannelScheduleSerializer(many=True, read_only=True)
    performance_records = CampaignPerformanceSerializer(many=True, read_only=True)
    
    status_display = serializers.CharField(source='get_status_display', read_only=True)
    type_display = serializers.CharField(source='get_campaign_type_display', read_only=True)
    budget_utilization = serializers.SerializerMethodField()
    days_remaining = serializers.SerializerMethodField()
    is_active = serializers.SerializerMethodField()
    can_be_activated = serializers.SerializerMethodField()
    
    class Meta:
        model = Campaign
        fields = [
            'id', 'name', 'description', 'campaign_type', 'type_display',
            'advertiser', 'geographic_zones', 'channels', 'status', 'status_display',
            'start_date', 'end_date', 'total_budget', 'daily_budget',
            'cost_per_spot', 'total_spend', 'budget_utilization',
            'total_impressions', 'priority', 'target_audience',
            'days_remaining', 'is_active', 'can_be_activated',
            'channel_schedules', 'performance_records',
            'created_at', 'updated_at'
        ]
    
    def get_budget_utilization(self, obj):
        return obj.budget_utilization()
    
    def get_days_remaining(self, obj):
        return obj.days_remaining()
    
    def get_is_active(self, obj):
        return obj.is_active()
    
    def get_can_be_activated(self, obj):
        return obj.can_be_activated()


class CampaignCreateUpdateSerializer(serializers.ModelSerializer):
    """
    Serializer for creating and updating campaigns.
    """
    advertiser_id = serializers.IntegerField(write_only=True)
    geographic_zone_ids = serializers.ListField(
        child=serializers.IntegerField(),
        write_only=True,
        required=False
    )
    channel_ids = serializers.ListField(
        child=serializers.IntegerField(),
        write_only=True,
        required=False
    )
    
    class Meta:
        model = Campaign
        fields = [
            'id', 'name', 'description', 'campaign_type', 'advertiser_id',
            'start_date', 'end_date', 'total_budget', 'daily_budget',
            'cost_per_spot', 'priority', 'target_audience',
            'geographic_zone_ids', 'channel_ids'
        ]
        read_only_fields = ['id']
    
    def validate(self, data):
        """
        Validate campaign data.
        """
        start_date = data.get('start_date')
        end_date = data.get('end_date')
        total_budget = data.get('total_budget')
        daily_budget = data.get('daily_budget')
        
        # Validate date range
        if start_date and end_date and start_date >= end_date:
            raise serializers.ValidationError({
                'end_date': _('End date must be after start date.')
            })
        
        # Validate budget
        if total_budget and daily_budget and start_date and end_date:
            campaign_days = (end_date.date() - start_date.date()).days + 1
            if daily_budget * campaign_days > total_budget:
                raise serializers.ValidationError({
                    'daily_budget': _('Daily budget × campaign days cannot exceed total budget.')
                })
        
        return data
    
    def validate_name(self, value):
        """
        Validate campaign name uniqueness.
        """
        queryset = Campaign.objects.filter(name__iexact=value)
        if self.instance:
            queryset = queryset.exclude(pk=self.instance.pk)
        
        if queryset.exists():
            raise serializers.ValidationError(
                _('A campaign with this name already exists.')
            )
        
        return value
    
    def create(self, validated_data):
        """
        Create a new campaign with related objects.
        """
        geographic_zone_ids = validated_data.pop('geographic_zone_ids', [])
        channel_ids = validated_data.pop('channel_ids', [])
        
        campaign = Campaign.objects.create(**validated_data)
        
        if geographic_zone_ids:
            campaign.geographic_zones.set(geographic_zone_ids)
        
        if channel_ids:
            campaign.channels.set(channel_ids)
        
        return campaign
    
    def update(self, instance, validated_data):
        """
        Update an existing campaign with related objects.
        """
        geographic_zone_ids = validated_data.pop('geographic_zone_ids', None)
        channel_ids = validated_data.pop('channel_ids', None)
        
        # Update campaign fields
        for attr, value in validated_data.items():
            setattr(instance, attr, value)
        instance.save()
        
        # Update related objects
        if geographic_zone_ids is not None:
            instance.geographic_zones.set(geographic_zone_ids)
        
        if channel_ids is not None:
            instance.channels.set(channel_ids)
        
        return instance


class CampaignStatsSerializer(serializers.Serializer):
    """
    Serializer for campaign statistics.
    """
    total_campaigns = serializers.IntegerField()
    active_campaigns = serializers.IntegerField()
    pending_campaigns = serializers.IntegerField()
    completed_campaigns = serializers.IntegerField()
    paused_campaigns = serializers.IntegerField()
    total_budget = serializers.DecimalField(max_digits=15, decimal_places=2)
    total_spend = serializers.DecimalField(max_digits=15, decimal_places=2)
    total_impressions = serializers.IntegerField()
    average_cpm = serializers.DecimalField(max_digits=10, decimal_places=2)


class CampaignPerformanceChartSerializer(serializers.Serializer):
    """
    Serializer for campaign performance chart data.
    """
    dates = serializers.ListField(child=serializers.DateField())
    impressions = serializers.ListField(child=serializers.IntegerField())
    spend = serializers.ListField(child=serializers.DecimalField(max_digits=10, decimal_places=2))
    spots = serializers.ListField(child=serializers.IntegerField())
    cpm = serializers.ListField(child=serializers.DecimalField(max_digits=10, decimal_places=2))