# -*- coding: utf-8 -*-
"""
Analytics Serializers
=====================

Django REST Framework serializers for the Adtlas Analytics module.
These serializers handle data serialization and deserialization for API endpoints,
data validation, and transformation for the analytics system.

Serializer Classes:
- SfrAnalyticsSerializer: SFR analytics data serialization
- BouyguesAnalyticsSerializer: Bouygues analytics data serialization
- ImpressionSerializer: Individual impression tracking
- VastResponseSerializer: VAST response data
- PerformanceMetricSerializer: Aggregated performance metrics
- AnalyticsReportSerializer: Report metadata
- AnalyticsDashboardSerializer: Dashboard data aggregation
- AnalyticsExportSerializer: Data export functionality

Key Features:
- Data validation and sanitization
- Nested serialization for related objects
- Custom field transformations
- Performance optimization
- Security and privacy protection
- Flexible filtering and aggregation

API Endpoints Support:
- GET /api/analytics/sfr/
- GET /api/analytics/bouygues/
- GET /api/analytics/impressions/
- GET /api/analytics/performance/
- POST /api/analytics/reports/
- GET /api/analytics/dashboard/

Author: Adtlas Development Team
Version: 1.0.0
Last Updated: 2024
"""

from rest_framework import serializers
from django.utils.translation import gettext_lazy as _
from django.utils import timezone
from django.db.models import Sum, Avg, Count
from decimal import Decimal
import json

from .models import (
    SfrAnalytics,
    BouyguesAnalytics,
    Impression,
    VastResponse,
    PerformanceMetric,
    AnalyticsReport
)


class BaseAnalyticsSerializer(serializers.ModelSerializer):
    """
    Base serializer for analytics models.
    
    Provides common functionality for all analytics serializers:
    - Standard field handling
    - Date/time formatting
    - Performance optimization
    - Security measures
    
    Common Fields:
        id: UUID primary key
        created_at: Creation timestamp
        updated_at: Last update timestamp
        is_active: Active status
    """
    
    # Read-only fields that are automatically managed
    id = serializers.UUIDField(read_only=True)
    created_at = serializers.DateTimeField(read_only=True)
    updated_at = serializers.DateTimeField(read_only=True)
    is_active = serializers.BooleanField(read_only=True)
    
    class Meta:
        abstract = True
    
    def validate(self, attrs):
        """
        Perform cross-field validation.
        
        Args:
            attrs (dict): Validated attributes
            
        Returns:
            dict: Validated and cleaned attributes
            
        Raises:
            ValidationError: If validation fails
        """
        # Ensure dates are not in the future for historical data
        if 'date' in attrs and attrs['date'] > timezone.now().date():
            raise serializers.ValidationError({
                'date': _('Date cannot be in the future for analytics data.')
            })
        
        return super().validate(attrs)
    
    def to_representation(self, instance):
        """
        Convert model instance to serialized representation.
        
        Args:
            instance: Model instance to serialize
            
        Returns:
            dict: Serialized representation
        """
        data = super().to_representation(instance)
        
        # Format decimal fields to 2 decimal places
        for field_name, field in self.fields.items():
            if isinstance(field, serializers.DecimalField) and field_name in data:
                if data[field_name] is not None:
                    data[field_name] = f"{float(data[field_name]):.2f}"
        
        return data


class SfrAnalyticsSerializer(BaseAnalyticsSerializer):
    """
    Serializer for SFR Analytics data.
    
    Handles serialization of SFR analytics data including audience metrics,
    market share, and demographic information.
    
    Fields:
        channel: Channel information (nested)
        campaign: Campaign information (nested, optional)
        date: Analytics date
        hour: Hour of the day
        audience_count: Number of viewers
        market_share: Market share percentage
        rating: Audience rating
        reach: Reach percentage
        frequency: Average frequency
        duration: Viewing duration
        demographics: Demographic data
        geographic_data: Geographic distribution
        performance_score: Calculated performance score
        datetime: Combined date and hour
    """
    
    # Nested serializers for related objects
    channel = serializers.StringRelatedField(read_only=True)
    campaign = serializers.StringRelatedField(read_only=True)
    
    # Calculated fields
    performance_score = serializers.SerializerMethodField()
    datetime = serializers.SerializerMethodField()
    
    # Custom field representations
    demographics = serializers.JSONField(required=False)
    geographic_data = serializers.JSONField(required=False)
    
    class Meta:
        model = SfrAnalytics
        fields = [
            'id', 'channel', 'campaign', 'date', 'hour',
            'audience_count', 'market_share', 'rating', 'reach',
            'frequency', 'duration', 'demographics', 'geographic_data',
            'performance_score', 'datetime', 'created_at', 'updated_at'
        ]
        read_only_fields = ['id', 'created_at', 'updated_at']
    
    def get_performance_score(self, obj):
        """
        Get calculated performance score.
        
        Args:
            obj: SfrAnalytics instance
            
        Returns:
            float: Performance score
        """
        return obj.get_performance_score()
    
    def get_datetime(self, obj):
        """
        Get combined datetime for the analytics record.
        
        Args:
            obj: SfrAnalytics instance
            
        Returns:
            str: ISO formatted datetime
        """
        return obj.datetime.isoformat() if hasattr(obj, 'datetime') else None
    
    def validate_hour(self, value):
        """
        Validate hour field.
        
        Args:
            value (int): Hour value
            
        Returns:
            int: Validated hour
            
        Raises:
            ValidationError: If hour is invalid
        """
        if not 0 <= value <= 23:
            raise serializers.ValidationError(
                _('Hour must be between 0 and 23.')
            )
        return value
    
    def validate_demographics(self, value):
        """
        Validate demographics JSON data.
        
        Args:
            value (dict): Demographics data
            
        Returns:
            dict: Validated demographics data
        """
        if value and not isinstance(value, dict):
            raise serializers.ValidationError(
                _('Demographics must be a valid JSON object.')
            )
        return value or {}


class BouyguesAnalyticsSerializer(BaseAnalyticsSerializer):
    """
    Serializer for Bouygues Analytics data.
    
    Similar to SFR analytics but with Bouygues-specific field names
    and data structures.
    
    Fields:
        channel: Channel information
        campaign: Campaign information (optional)
        date: Analytics date
        hour: Hour of the day
        viewers: Number of viewers
        share: Market share percentage
        rating_value: Audience rating
        reach_percentage: Reach percentage
        avg_frequency: Average frequency
        watch_time: Watch time in minutes
        device_data: Device breakdown
        age_groups: Age group data
    """
    
    # Nested serializers for related objects
    channel = serializers.StringRelatedField(read_only=True)
    campaign = serializers.StringRelatedField(read_only=True)
    
    # Custom field representations
    device_data = serializers.JSONField(required=False)
    age_groups = serializers.JSONField(required=False)
    
    class Meta:
        model = BouyguesAnalytics
        fields = [
            'id', 'channel', 'campaign', 'date', 'hour',
            'viewers', 'share', 'rating_value', 'reach_percentage',
            'avg_frequency', 'watch_time', 'device_data', 'age_groups',
            'created_at', 'updated_at'
        ]
        read_only_fields = ['id', 'created_at', 'updated_at']
    
    def validate_device_data(self, value):
        """
        Validate device data JSON.
        
        Args:
            value (dict): Device data
            
        Returns:
            dict: Validated device data
        """
        if value and not isinstance(value, dict):
            raise serializers.ValidationError(
                _('Device data must be a valid JSON object.')
            )
        return value or {}


class ImpressionSerializer(BaseAnalyticsSerializer):
    """
    Serializer for individual impression tracking.
    
    Handles serialization of impression data with privacy protection
    for sensitive information like IP addresses.
    
    Fields:
        campaign: Campaign information
        adspot: Ad spot information
        channel: Channel information
        timestamp: Impression timestamp
        duration: View duration
        completion_rate: Completion percentage
        click_through: Click-through flag
        vast_response: Related VAST response
        is_completed: Calculated completion status
        is_viewable: Calculated viewability status
    """
    
    # Nested serializers for related objects
    campaign = serializers.StringRelatedField(read_only=True)
    adspot = serializers.StringRelatedField(read_only=True)
    channel = serializers.StringRelatedField(read_only=True)
    vast_response = serializers.StringRelatedField(read_only=True)
    
    # Calculated fields
    is_completed = serializers.SerializerMethodField()
    is_viewable = serializers.SerializerMethodField()
    
    # Privacy-protected fields
    ip_address = serializers.CharField(write_only=True, required=False)
    user_agent = serializers.CharField(write_only=True, required=False)
    
    class Meta:
        model = Impression
        fields = [
            'id', 'campaign', 'adspot', 'channel', 'timestamp',
            'duration', 'completion_rate', 'click_through',
            'vast_response', 'is_completed', 'is_viewable',
            'geographic_info', 'device_info', 'created_at'
        ]
        read_only_fields = ['id', 'created_at']
    
    def get_is_completed(self, obj):
        """
        Get completion status.
        
        Args:
            obj: Impression instance
            
        Returns:
            bool: Whether impression was completed
        """
        return obj.is_completed
    
    def get_is_viewable(self, obj):
        """
        Get viewability status.
        
        Args:
            obj: Impression instance
            
        Returns:
            bool: Whether impression meets viewability standards
        """
        return obj.is_viewable
    
    def validate_completion_rate(self, value):
        """
        Validate completion rate.
        
        Args:
            value (Decimal): Completion rate
            
        Returns:
            Decimal: Validated completion rate
        """
        if value < 0 or value > 100:
            raise serializers.ValidationError(
                _('Completion rate must be between 0 and 100.')
            )
        return value
    
    def create(self, validated_data):
        """
        Create impression with privacy protection.
        
        Args:
            validated_data (dict): Validated data
            
        Returns:
            Impression: Created impression instance
        """
        # Anonymize IP address for privacy
        if 'ip_address' in validated_data:
            ip = validated_data['ip_address']
            if ip:
                # Simple anonymization - replace last octet with 0
                parts = ip.split('.')
                if len(parts) == 4:
                    parts[-1] = '0'
                    validated_data['ip_address'] = '.'.join(parts)
        
        return super().create(validated_data)


class VastResponseSerializer(BaseAnalyticsSerializer):
    """
    Serializer for VAST response tracking.
    
    Handles VAST response data including performance metrics
    and tracking information.
    
    Fields:
        campaign: Campaign information
        adspot: Ad spot information
        vast_url: VAST XML URL
        response_time: Response time in milliseconds
        status_code: HTTP status code
        error_message: Error message if any
        tracking_urls: Tracking URLs
        creative_info: Creative information
        served_at: Service timestamp
        is_successful: Success status
        is_fast_response: Response speed status
    """
    
    # Nested serializers for related objects
    campaign = serializers.StringRelatedField(read_only=True)
    adspot = serializers.StringRelatedField(read_only=True)
    
    # Calculated fields
    is_successful = serializers.SerializerMethodField()
    is_fast_response = serializers.SerializerMethodField()
    
    # JSON fields
    tracking_urls = serializers.JSONField(required=False)
    creative_info = serializers.JSONField(required=False)
    
    class Meta:
        model = VastResponse
        fields = [
            'id', 'campaign', 'adspot', 'vast_url', 'response_time',
            'status_code', 'error_message', 'tracking_urls',
            'creative_info', 'served_at', 'is_successful',
            'is_fast_response', 'created_at'
        ]
        read_only_fields = ['id', 'created_at']
    
    def get_is_successful(self, obj):
        """
        Get success status.
        
        Args:
            obj: VastResponse instance
            
        Returns:
            bool: Whether response was successful
        """
        return obj.is_successful
    
    def get_is_fast_response(self, obj):
        """
        Get response speed status.
        
        Args:
            obj: VastResponse instance
            
        Returns:
            bool: Whether response was fast enough
        """
        return obj.is_fast_response


class PerformanceMetricSerializer(BaseAnalyticsSerializer):
    """
    Serializer for aggregated performance metrics.
    
    Handles performance data aggregation and calculation
    for reporting and dashboard purposes.
    
    Fields:
        campaign: Campaign information
        channel: Channel information (optional)
        date: Metrics date
        metric_type: Type of aggregation
        impressions_count: Total impressions
        clicks_count: Total clicks
        completion_rate: Average completion rate
        ctr: Click-through rate
        cpm: Cost per mille
        revenue: Total revenue
        cost: Total cost
        roi: Return on investment
    """
    
    # Nested serializers for related objects
    campaign = serializers.StringRelatedField(read_only=True)
    channel = serializers.StringRelatedField(read_only=True)
    
    class Meta:
        model = PerformanceMetric
        fields = [
            'id', 'campaign', 'channel', 'date', 'metric_type',
            'impressions_count', 'clicks_count', 'completion_rate',
            'ctr', 'cpm', 'revenue', 'cost', 'roi',
            'created_at', 'updated_at'
        ]
        read_only_fields = ['id', 'created_at', 'updated_at']
    
    def validate(self, attrs):
        """
        Validate performance metric data.
        
        Args:
            attrs (dict): Validated attributes
            
        Returns:
            dict: Validated attributes
        """
        attrs = super().validate(attrs)
        
        # Validate that clicks don't exceed impressions
        if ('clicks_count' in attrs and 'impressions_count' in attrs and
                attrs['clicks_count'] > attrs['impressions_count']):
            raise serializers.ValidationError({
                'clicks_count': _('Clicks cannot exceed impressions.')
            })
        
        return attrs
    
    def create(self, validated_data):
        """
        Create performance metric with calculated fields.
        
        Args:
            validated_data (dict): Validated data
            
        Returns:
            PerformanceMetric: Created instance
        """
        instance = super().create(validated_data)
        
        # Calculate derived metrics
        instance.calculate_ctr()
        instance.calculate_roi()
        instance.save(update_fields=['ctr', 'roi'])
        
        return instance


class AnalyticsReportSerializer(BaseAnalyticsSerializer):
    """
    Serializer for analytics report metadata.
    
    Handles report generation requests and metadata
    for tracking and caching purposes.
    
    Fields:
        name: Report name
        report_type: Type of report
        parameters: Report parameters
        file_size: File size in bytes
        generated_by: User who generated report
        generated_at: Generation timestamp
        expires_at: Expiration timestamp
        download_count: Download counter
        is_public: Public access flag
        is_expired: Expiration status
    """
    
    # Nested serializers for related objects
    generated_by = serializers.StringRelatedField(read_only=True)
    
    # Calculated fields
    is_expired = serializers.SerializerMethodField()
    file_size_formatted = serializers.SerializerMethodField()
    
    # JSON fields
    parameters = serializers.JSONField(required=False)
    
    class Meta:
        model = AnalyticsReport
        fields = [
            'id', 'name', 'report_type', 'parameters',
            'file_size', 'file_size_formatted', 'generated_by',
            'generated_at', 'expires_at', 'download_count',
            'is_public', 'is_expired', 'created_at'
        ]
        read_only_fields = [
            'id', 'file_size', 'generated_by', 'generated_at',
            'download_count', 'created_at'
        ]
    
    def get_is_expired(self, obj):
        """
        Get expiration status.
        
        Args:
            obj: AnalyticsReport instance
            
        Returns:
            bool: Whether report has expired
        """
        return obj.is_expired
    
    def get_file_size_formatted(self, obj):
        """
        Get formatted file size.
        
        Args:
            obj: AnalyticsReport instance
            
        Returns:
            str: Human-readable file size
        """
        size = obj.file_size
        if size < 1024:
            return f"{size} B"
        elif size < 1024 * 1024:
            return f"{size / 1024:.1f} KB"
        elif size < 1024 * 1024 * 1024:
            return f"{size / (1024 * 1024):.1f} MB"
        else:
            return f"{size / (1024 * 1024 * 1024):.1f} GB"


class AnalyticsDashboardSerializer(serializers.Serializer):
    """
    Serializer for analytics dashboard data.
    
    Aggregates and formats data for dashboard display
    including key performance indicators and charts.
    
    Fields:
        date_range: Date range for data
        total_impressions: Total impressions count
        total_clicks: Total clicks count
        average_ctr: Average click-through rate
        total_revenue: Total revenue
        top_campaigns: Top performing campaigns
        channel_performance: Performance by channel
        hourly_distribution: Hourly impression distribution
        completion_rates: Completion rate trends
    """
    
    # Date range
    start_date = serializers.DateField()
    end_date = serializers.DateField()
    
    # Key metrics
    total_impressions = serializers.IntegerField(read_only=True)
    total_clicks = serializers.IntegerField(read_only=True)
    average_ctr = serializers.DecimalField(max_digits=5, decimal_places=2, read_only=True)
    total_revenue = serializers.DecimalField(max_digits=12, decimal_places=2, read_only=True)
    
    # Aggregated data
    top_campaigns = serializers.ListField(read_only=True)
    channel_performance = serializers.ListField(read_only=True)
    hourly_distribution = serializers.ListField(read_only=True)
    completion_rates = serializers.ListField(read_only=True)
    
    def validate(self, attrs):
        """
        Validate dashboard parameters.
        
        Args:
            attrs (dict): Validated attributes
            
        Returns:
            dict: Validated attributes
        """
        start_date = attrs.get('start_date')
        end_date = attrs.get('end_date')
        
        if start_date and end_date:
            if start_date > end_date:
                raise serializers.ValidationError({
                    'start_date': _('Start date must be before end date.')
                })
            
            # Limit date range to prevent performance issues
            date_diff = (end_date - start_date).days
            if date_diff > 365:
                raise serializers.ValidationError({
                    'date_range': _('Date range cannot exceed 365 days.')
                })
        
        return attrs


class AnalyticsExportSerializer(serializers.Serializer):
    """
    Serializer for analytics data export.
    
    Handles export requests with filtering and formatting options
    for various data formats (CSV, Excel, JSON).
    
    Fields:
        export_type: Type of data to export
        format: Export format (csv, excel, json)
        date_range: Date range for export
        filters: Additional filters
        include_fields: Fields to include
        email_delivery: Whether to email the export
    """
    
    EXPORT_TYPES = [
        ('impressions', _('Impressions')),
        ('performance', _('Performance Metrics')),
        ('sfr_analytics', _('SFR Analytics')),
        ('bouygues_analytics', _('Bouygues Analytics')),
        ('vast_responses', _('VAST Responses')),
    ]
    
    EXPORT_FORMATS = [
        ('csv', _('CSV')),
        ('excel', _('Excel')),
        ('json', _('JSON')),
    ]
    
    # Export configuration
    export_type = serializers.ChoiceField(choices=EXPORT_TYPES)
    format = serializers.ChoiceField(choices=EXPORT_FORMATS, default='csv')
    
    # Date range
    start_date = serializers.DateField()
    end_date = serializers.DateField()
    
    # Filtering and options
    filters = serializers.JSONField(required=False, default=dict)
    include_fields = serializers.ListField(
        child=serializers.CharField(),
        required=False,
        allow_empty=True
    )
    
    # Delivery options
    email_delivery = serializers.BooleanField(default=False)
    
    def validate(self, attrs):
        """
        Validate export parameters.
        
        Args:
            attrs (dict): Validated attributes
            
        Returns:
            dict: Validated attributes
        """
        start_date = attrs.get('start_date')
        end_date = attrs.get('end_date')
        
        if start_date and end_date:
            if start_date > end_date:
                raise serializers.ValidationError({
                    'start_date': _('Start date must be before end date.')
                })
            
            # Limit export size to prevent performance issues
            date_diff = (end_date - start_date).days
            if date_diff > 90:
                raise serializers.ValidationError({
                    'date_range': _('Export date range cannot exceed 90 days.')
                })
        
        return attrs