"""Serializers for Reporting and Analytics app."""

from rest_framework import serializers
from django.contrib.auth import get_user_model
from decimal import Decimal

from .models import (
    AnalyticsRegion,
    AnalyticsTarget,
    SfrAnalytics,
    MarketShare,
    VerificationRecord,
    PredictionModel,
    SfrPrediction,
    AdbreakPrediction,
    ActivityLog,
    RealTimeAdbreak,
)
from apps.channels.serializers import ChannelSerializer
from apps.campaigns.serializers import CampaignSerializer
from apps.advertisers.serializers import BrandSerializer

User = get_user_model()


class UserBasicSerializer(serializers.ModelSerializer):
    """Basic user serializer for references."""
    
    class Meta:
        model = User
        fields = ['id', 'username', 'first_name', 'last_name', 'email']
        read_only_fields = fields


class AnalyticsRegionSerializer(serializers.ModelSerializer):
    """Serializer for AnalyticsRegion model."""
    
    class Meta:
        model = AnalyticsRegion
        fields = [
            'id', 'name', 'code', 'country', 'population', 'timezone_name',
            'created_at', 'updated_at'
        ]
        read_only_fields = ['id', 'created_at', 'updated_at']
    
    def validate_code(self, value):
        """Validate region code uniqueness."""
        if self.instance:
            # Update case - exclude current instance
            if AnalyticsRegion.objects.exclude(
                id=self.instance.id
            ).filter(code=value).exists():
                raise serializers.ValidationError(
                    "Region with this code already exists."
                )
        else:
            # Create case
            if AnalyticsRegion.objects.filter(code=value).exists():
                raise serializers.ValidationError(
                    "Region with this code already exists."
                )
        return value


class AnalyticsTargetSerializer(serializers.ModelSerializer):
    """Serializer for AnalyticsTarget model."""
    
    age_range = serializers.SerializerMethodField()
    
    class Meta:
        model = AnalyticsTarget
        fields = [
            'id', 'name', 'code', 'description', 'age_min', 'age_max',
            'gender', 'age_range', 'created_at', 'updated_at'
        ]
        read_only_fields = ['id', 'age_range', 'created_at', 'updated_at']
    
    def get_age_range(self, obj):
        """Get formatted age range."""
        if obj.age_min and obj.age_max:
            return f"{obj.age_min}-{obj.age_max}"
        elif obj.age_min:
            return f"{obj.age_min}+"
        elif obj.age_max:
            return f"<{obj.age_max}"
        return "All ages"
    
    def validate(self, data):
        """Validate age range."""
        age_min = data.get('age_min')
        age_max = data.get('age_max')
        
        if age_min and age_max and age_min >= age_max:
            raise serializers.ValidationError(
                "Minimum age must be less than maximum age."
            )
        
        return data


class SfrAnalyticsSerializer(serializers.ModelSerializer):
    """Serializer for SfrAnalytics model."""
    
    channel_name = serializers.CharField(source='channel.name', read_only=True)
    region_name = serializers.CharField(source='region.name', read_only=True)
    target_name = serializers.CharField(source='target.name', read_only=True)
    indicator_display = serializers.CharField(source='get_indicator_display', read_only=True)
    
    class Meta:
        model = SfrAnalytics
        fields = [
            'id', 'channel', 'channel_name', 'sfr_channel_name',
            'measurement_date', 'measurement_time', 'region', 'region_name',
            'target', 'target_name', 'indicator', 'indicator_display',
            'value', 'percentage', 'raw_data', 'data_source',
            'quality_score', 'created_at', 'updated_at'
        ]
        read_only_fields = ['id', 'created_at', 'updated_at']
    
    def validate_value(self, value):
        """Validate measurement value."""
        if value < 0:
            raise serializers.ValidationError(
                "Measurement value cannot be negative."
            )
        return value
    
    def validate_quality_score(self, value):
        """Validate quality score range."""
        if value is not None and (value < 0 or value > 1):
            raise serializers.ValidationError(
                "Quality score must be between 0 and 1."
            )
        return value


class MarketShareSerializer(serializers.ModelSerializer):
    """Serializer for MarketShare model."""
    
    channel_name = serializers.CharField(source='channel.name', read_only=True)
    region_name = serializers.CharField(source='region.name', read_only=True)
    target_name = serializers.CharField(source='target.name', read_only=True)
    
    class Meta:
        model = MarketShare
        fields = [
            'id', 'channel', 'channel_name', 'measurement_date',
            'region', 'region_name', 'target', 'target_name',
            'total_users', 'channel_users', 'market_share_percentage',
            'ranking', 'tool_name', 'created_at', 'updated_at'
        ]
        read_only_fields = ['id', 'created_at', 'updated_at']
    
    def validate(self, data):
        """Validate market share data."""
        total_users = data.get('total_users')
        channel_users = data.get('channel_users')
        
        if total_users and channel_users and channel_users > total_users:
            raise serializers.ValidationError(
                "Channel users cannot exceed total users."
            )
        
        market_share = data.get('market_share_percentage')
        if market_share and (market_share < 0 or market_share > 100):
            raise serializers.ValidationError(
                "Market share percentage must be between 0 and 100."
            )
        
        return data


class VerificationRecordSerializer(serializers.ModelSerializer):
    """Serializer for VerificationRecord model."""
    
    campaign_name = serializers.CharField(source='campaign.name', read_only=True)
    advertiser_name = serializers.CharField(source='advertiser.name', read_only=True)
    verified_by_username = serializers.CharField(source='verified_by.username', read_only=True)
    status_display = serializers.CharField(source='get_status_display', read_only=True)
    
    class Meta:
        model = VerificationRecord
        fields = [
            'id', 'network_name', 'zone_name', 'broadcast_date',
            'broadcast_time', 'traffic_id', 'spot_id', 'air_time',
            'air_length', 'air_status_code', 'revision',
            'verification_complete', 'status', 'status_display',
            'campaign', 'campaign_name', 'advertiser', 'advertiser_name',
            'verification_data', 'error_message', 'verified_by',
            'verified_by_username', 'verified_at', 'created_at', 'updated_at'
        ]
        read_only_fields = [
            'id', 'verified_by_username', 'campaign_name', 'advertiser_name',
            'status_display', 'created_at', 'updated_at'
        ]
    
    def validate_traffic_id(self, value):
        """Validate traffic ID."""
        if value <= 0:
            raise serializers.ValidationError(
                "Traffic ID must be a positive integer."
            )
        return value


class PredictionModelSerializer(serializers.ModelSerializer):
    """Serializer for PredictionModel model."""
    
    model_type_display = serializers.CharField(source='get_model_type_display', read_only=True)
    predictions_count = serializers.SerializerMethodField()
    
    class Meta:
        model = PredictionModel
        fields = [
            'id', 'name', 'model_type', 'model_type_display', 'description',
            'algorithm', 'version', 'accuracy_score', 'training_data_start',
            'training_data_end', 'is_active', 'parameters', 'predictions_count',
            'created_at', 'updated_at'
        ]
        read_only_fields = [
            'id', 'model_type_display', 'predictions_count',
            'created_at', 'updated_at'
        ]
    
    def get_predictions_count(self, obj):
        """Get total number of predictions made by this model."""
        return obj.sfr_predictions.count() + obj.adbreak_predictions.count()
    
    def validate_accuracy_score(self, value):
        """Validate accuracy score range."""
        if value is not None and (value < 0 or value > 1):
            raise serializers.ValidationError(
                "Accuracy score must be between 0 and 1."
            )
        return value
    
    def validate(self, data):
        """Validate training data dates."""
        start_date = data.get('training_data_start')
        end_date = data.get('training_data_end')
        
        if start_date and end_date and start_date >= end_date:
            raise serializers.ValidationError(
                "Training data start date must be before end date."
            )
        
        return data


class SfrPredictionSerializer(serializers.ModelSerializer):
    """Serializer for SfrPrediction model."""
    
    model_name = serializers.CharField(source='model.name', read_only=True)
    channel_name = serializers.CharField(source='channel.name', read_only=True)
    region_name = serializers.CharField(source='region.name', read_only=True)
    target_name = serializers.CharField(source='target.name', read_only=True)
    indicator_display = serializers.CharField(source='get_indicator_display', read_only=True)
    accuracy = serializers.SerializerMethodField()
    
    class Meta:
        model = SfrPrediction
        fields = [
            'id', 'model', 'model_name', 'channel', 'channel_name',
            'sfr_channel_name', 'prediction_date', 'prediction_time',
            'region', 'region_name', 'target', 'target_name',
            'indicator', 'indicator_display', 'predicted_value',
            'predicted_percentage', 'confidence_score', 'actual_value',
            'accuracy', 'created_at', 'updated_at'
        ]
        read_only_fields = [
            'id', 'model_name', 'channel_name', 'region_name',
            'target_name', 'indicator_display', 'accuracy',
            'created_at', 'updated_at'
        ]
    
    def get_accuracy(self, obj):
        """Get prediction accuracy as percentage."""
        accuracy = obj.accuracy
        if accuracy is not None:
            return round(accuracy * 100, 2)
        return None
    
    def validate_predicted_value(self, value):
        """Validate predicted value."""
        if value < 0:
            raise serializers.ValidationError(
                "Predicted value cannot be negative."
            )
        return value
    
    def validate_confidence_score(self, value):
        """Validate confidence score range."""
        if value is not None and (value < 0 or value > 1):
            raise serializers.ValidationError(
                "Confidence score must be between 0 and 1."
            )
        return value


class AdbreakPredictionSerializer(serializers.ModelSerializer):
    """Serializer for AdbreakPrediction model."""
    
    model_name = serializers.CharField(source='model.name', read_only=True)
    channel_name = serializers.CharField(source='channel.name', read_only=True)
    timing_accuracy_minutes = serializers.SerializerMethodField()
    
    class Meta:
        model = AdbreakPrediction
        fields = [
            'id', 'model', 'model_name', 'channel', 'channel_name',
            'prediction_datetime', 'prediction_date', 'prediction_time',
            'predicted_duration', 'predicted_duration_seconds',
            'confidence_score', 'actual_datetime', 'actual_duration_seconds',
            'timing_accuracy_minutes', 'created_at', 'updated_at'
        ]
        read_only_fields = [
            'id', 'model_name', 'channel_name', 'timing_accuracy_minutes',
            'created_at', 'updated_at'
        ]
    
    def get_timing_accuracy_minutes(self, obj):
        """Get timing accuracy in minutes."""
        accuracy = obj.timing_accuracy_minutes
        if accuracy is not None:
            return round(accuracy, 2)
        return None
    
    def validate_predicted_duration_seconds(self, value):
        """Validate predicted duration."""
        if value is not None and value <= 0:
            raise serializers.ValidationError(
                "Predicted duration must be positive."
            )
        return value
    
    def validate_confidence_score(self, value):
        """Validate confidence score range."""
        if value is not None and (value < 0 or value > 1):
            raise serializers.ValidationError(
                "Confidence score must be between 0 and 1."
            )
        return value


class ActivityLogSerializer(serializers.ModelSerializer):
    """Serializer for ActivityLog model."""
    
    user_username = serializers.CharField(source='user.username', read_only=True)
    activity_type_display = serializers.CharField(source='get_activity_type_display', read_only=True)
    
    class Meta:
        model = ActivityLog
        fields = [
            'id', 'activity_type', 'activity_type_display', 'activity_date',
            'description', 'user', 'user_username', 'ip_address',
            'user_agent', 'additional_data', 'created_at', 'updated_at'
        ]
        read_only_fields = [
            'id', 'user_username', 'activity_type_display',
            'created_at', 'updated_at'
        ]


class RealTimeAdbreakSerializer(serializers.ModelSerializer):
    """Serializer for RealTimeAdbreak model."""
    
    channel_name = serializers.CharField(source='channel.name', read_only=True)
    status_display = serializers.CharField(source='get_status_display', read_only=True)
    actual_duration_seconds = serializers.SerializerMethodField()
    duration_display = serializers.SerializerMethodField()
    
    class Meta:
        model = RealTimeAdbreak
        fields = [
            'id', 'channel', 'channel_name', 'start_time', 'end_time',
            'duration_seconds', 'actual_duration_seconds', 'duration_display',
            'status', 'status_display', 'ad_count', 'total_revenue',
            'viewer_count', 'tracking_data', 'created_at', 'updated_at'
        ]
        read_only_fields = [
            'id', 'channel_name', 'status_display', 'actual_duration_seconds',
            'duration_display', 'created_at', 'updated_at'
        ]
    
    def get_actual_duration_seconds(self, obj):
        """Get actual duration in seconds."""
        return obj.actual_duration_seconds
    
    def get_duration_display(self, obj):
        """Get formatted duration display."""
        duration = obj.actual_duration_seconds
        if duration:
            minutes = duration // 60
            seconds = duration % 60
            return f"{minutes}:{seconds:02d}"
        return None
    
    def validate_total_revenue(self, value):
        """Validate total revenue."""
        if value is not None and value < 0:
            raise serializers.ValidationError(
                "Total revenue cannot be negative."
            )
        return value
    
    def validate(self, data):
        """Validate ad break timing."""
        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(
                "Start time must be before end time."
            )
        
        return data


# Nested serializers for detailed views
class SfrAnalyticsDetailSerializer(SfrAnalyticsSerializer):
    """Detailed serializer for SfrAnalytics with related objects."""
    
    channel = ChannelSerializer(read_only=True)
    region = AnalyticsRegionSerializer(read_only=True)
    target = AnalyticsTargetSerializer(read_only=True)


class MarketShareDetailSerializer(MarketShareSerializer):
    """Detailed serializer for MarketShare with related objects."""
    
    channel = ChannelSerializer(read_only=True)
    region = AnalyticsRegionSerializer(read_only=True)
    target = AnalyticsTargetSerializer(read_only=True)


class VerificationRecordDetailSerializer(VerificationRecordSerializer):
    """Detailed serializer for VerificationRecord with related objects."""
    
    campaign = CampaignSerializer(read_only=True)
    advertiser = BrandSerializer(read_only=True)
    verified_by = UserBasicSerializer(read_only=True)


class SfrPredictionDetailSerializer(SfrPredictionSerializer):
    """Detailed serializer for SfrPrediction with related objects."""
    
    model = PredictionModelSerializer(read_only=True)
    channel = ChannelSerializer(read_only=True)
    region = AnalyticsRegionSerializer(read_only=True)
    target = AnalyticsTargetSerializer(read_only=True)


class AdbreakPredictionDetailSerializer(AdbreakPredictionSerializer):
    """Detailed serializer for AdbreakPrediction with related objects."""
    
    model = PredictionModelSerializer(read_only=True)
    channel = ChannelSerializer(read_only=True)


class RealTimeAdbreakDetailSerializer(RealTimeAdbreakSerializer):
    """Detailed serializer for RealTimeAdbreak with related objects."""
    
    channel = ChannelSerializer(read_only=True)