"""Advertisers Serializers

This module contains DRF serializers for the advertisers app.
Handles serialization and deserialization of advertiser-related data.

Serializers:
    - AgencySerializer: Basic agency serialization
    - AgencyDetailSerializer: Detailed agency with relationships
    - BrandSerializer: Basic brand serialization
    - BrandDetailSerializer: Detailed brand with relationships
    - BrandCategorySerializer: Brand category serialization
    - UserAdvertiserSerializer: User-advertiser relationship serialization
"""

from rest_framework import serializers
from django.contrib.auth import get_user_model
from django.db.models import Count, Sum

from .models import Agency, Brand, BrandCategory, UserAdvertiser 


User = get_user_model()


class BrandCategorySerializer(serializers.Serializer):
    """Serializer for BrandCategory model.
    
    Handles hierarchical category structure with parent-child relationships.
    """
    
    subcategories = serializers.SerializerMethodField()
    parent_name = serializers.CharField(source='parent.name', read_only=True)
    brands_count = serializers.SerializerMethodField()
    
    class Meta:
        model = BrandCategory
        fields = [
            'id', 'name', 'description', 'parent', 'parent_name',
            'subcategories', 'brands_count', 'created_at', 'updated_at'
        ]
        read_only_fields = ['id', 'created_at', 'updated_at']
    
    def get_subcategories(self, obj):
        """Get subcategories for hierarchical display."""
        if hasattr(obj, 'subcategories'):
            return BrandCategorySerializer(
                obj.subcategories.all(), 
                many=True, 
                context=self.context
            ).data
        return []
    
    def get_brands_count(self, obj):
        """Get number of brands in this category."""
        return obj.brands.filter(status='active').count()


class AgencySerializer(serializers.Serializer):
    """Basic serializer for Agency model.
    
    Used for list views and basic operations.
    """
    
    owner_name = serializers.CharField(source='owner.get_full_name', read_only=True)
    brands_count = serializers.SerializerMethodField()
    campaigns_count = serializers.SerializerMethodField()
    
    class Meta:
        model = Agency
        fields = [
            'id', 'name', 'description', 'email', 'phone', 'website',
            'address', 'city', 'country', 'logo', 'contact_person',
            'owner', 'owner_name', 'brands_count', 'campaigns_count',
            'status', 'created_at', 'updated_at'
        ]
        read_only_fields = ['id', 'owner', 'created_at', 'updated_at']
    
    def get_brands_count(self, obj):
        """Get total number of active brands for this agency."""
        return obj.brands.filter(status='active').count()
    
    def get_campaigns_count(self, obj):
        """Get total number of campaigns for this agency."""
        return obj.total_campaigns
    
    def validate_email(self, value):
        """Validate agency email uniqueness."""
        if Agency.objects.filter(email=value).exclude(id=self.instance.id if self.instance else None).exists():
            raise serializers.ValidationError("An agency with this email already exists.")
        return value


class BrandSerializer(serializers.Serializer):
    """Basic serializer for Brand model.
    
    Used for list views and basic operations.
    """
    
    agency_name = serializers.CharField(source='agency.name', read_only=True)
    category_name = serializers.CharField(source='category.name', read_only=True)
    campaigns_count = serializers.SerializerMethodField()
    active_campaigns_count = serializers.SerializerMethodField()
    
    class Meta:
        model = Brand
        fields = [
            'id', 'name', 'description', 'category', 'category_name',
            'agency', 'agency_name', 'logo', 'website', 'contact_email',
            'contact_phone', 'industry', 'target_audience', 'annual_budget',
            'campaigns_count', 'active_campaigns_count', 'status',
            'created_at', 'updated_at'
        ]
        read_only_fields = ['id', 'created_at', 'updated_at']
    
    def get_campaigns_count(self, obj):
        """Get total number of campaigns for this brand."""
        return obj.total_campaigns
    
    def get_active_campaigns_count(self, obj):
        """Get number of currently active campaigns."""
        return obj.active_campaigns.count()
    
    def validate(self, data):
        """Validate brand data."""
        # Check if brand name is unique within the agency
        agency = data.get('agency')
        name = data.get('name')
        
        if agency and name:
            existing_brand = Brand.objects.filter(
                agency=agency, 
                name=name
            ).exclude(id=self.instance.id if self.instance else None)
            
            if existing_brand.exists():
                raise serializers.ValidationError({
                    'name': 'A brand with this name already exists in this agency.'
                })
        
        return data


class AgencyDetailSerializer(AgencySerializer):
    """Detailed serializer for Agency model.
    
    Includes related brands and additional statistics.
    Used for detail views and comprehensive data display.
    """
    
    brands = BrandSerializer(many=True, read_only=True)
    total_budget = serializers.SerializerMethodField()
    recent_brands = serializers.SerializerMethodField()
    
    class Meta(AgencySerializer.Meta):
        fields = AgencySerializer.Meta.fields + [
            'brands', 'total_budget', 'recent_brands'
        ]
    
    def get_total_budget(self, obj):
        """Calculate total budget across all brands."""
        result = obj.brands.aggregate(total=Sum('annual_budget'))
        return float(result['total']) if result['total'] else 0.0
    
    def get_recent_brands(self, obj):
        """Get recently created brands for this agency."""
        recent_brands = obj.brands.filter(status='active').order_by('-created_at')[:5]
        return BrandSerializer(recent_brands, many=True, context=self.context).data


class BrandDetailSerializer(BrandSerializer):
    """Detailed serializer for Brand model.
    
    Includes related campaigns and additional statistics.
    Used for detail views and comprehensive data display.
    """
    
    agency_detail = AgencySerializer(source='agency', read_only=True)
    category_detail = BrandCategorySerializer(source='category', read_only=True)
    user_relationships = serializers.SerializerMethodField()
    budget_spent = serializers.SerializerMethodField()
    recent_campaigns = serializers.SerializerMethodField()
    
    class Meta(BrandSerializer.Meta):
        fields = BrandSerializer.Meta.fields + [
            'agency_detail', 'category_detail', 'user_relationships',
            'budget_spent', 'recent_campaigns'
        ]
    
    def get_user_relationships(self, obj):
        """Get users associated with this brand."""
        relationships = obj.user_relationships.filter(is_active=True)
        return UserAdvertiserSerializer(relationships, many=True, context=self.context).data
    
    def get_budget_spent(self, obj):
        """Get total budget spent across campaigns."""
        return float(obj.total_budget_spent)
    
    def get_recent_campaigns(self, obj):
        """Get recent campaigns for this brand."""
        # Import here to avoid circular imports
        from apps.campaigns.serializers import CampaignSerializer
        
        recent_campaigns = obj.campaigns.filter(status='active').order_by('-created_at')[:5]
        return CampaignSerializer(recent_campaigns, many=True, context=self.context).data


class UserAdvertiserSerializer(serializers.Serializer):
    """Serializer for UserAdvertiser relationship model.
    
    Handles user-brand relationships with roles and permissions.
    """
    
    user_name = serializers.CharField(source='user.get_full_name', read_only=True)
    user_email = serializers.CharField(source='user.email', read_only=True)
    brand_name = serializers.CharField(source='brand.name', read_only=True)
    agency_name = serializers.CharField(source='brand.agency.name', read_only=True)
    
    class Meta:
        model = UserAdvertiser
        fields = [
            'id', 'user', 'user_name', 'user_email', 'brand', 'brand_name',
            'agency_name', 'role', 'permissions', 'is_active',
            'created_at', 'updated_at'
        ]
        read_only_fields = ['id', 'created_at', 'updated_at']
    
    def validate(self, data):
        """Validate user-advertiser relationship."""
        user = data.get('user')
        brand = data.get('brand')
        
        if user and brand:
            # Check if relationship already exists
            existing_relationship = UserAdvertiser.objects.filter(
                user=user, 
                brand=brand
            ).exclude(id=self.instance.id if self.instance else None)
            
            if existing_relationship.exists():
                raise serializers.ValidationError({
                    'non_field_errors': ['This user-brand relationship already exists.']
                })
        
        return data
    
    def validate_permissions(self, value):
        """Validate permissions JSON structure."""
        if not isinstance(value, dict):
            raise serializers.ValidationError("Permissions must be a valid JSON object.")
        
        # Ensure required keys exist
        if 'allowed' not in value:
            value['allowed'] = []
        
        return value


class AgencyStatsSerializer(serializers.Serializer):
    """Serializer for agency statistics.
    
    Used for dashboard and reporting views.
    """
    
    total_brands = serializers.IntegerField()
    total_campaigns = serializers.IntegerField()
    active_campaigns = serializers.IntegerField()
    total_budget = serializers.DecimalField(max_digits=12, decimal_places=2)
    brands_by_category = serializers.DictField()
    monthly_growth = serializers.DictField()


class BrandStatsSerializer(serializers.Serializer):
    """Serializer for brand statistics.
    
    Used for dashboard and reporting views.
    """
    
    total_campaigns = serializers.IntegerField()
    active_campaigns = serializers.IntegerField()
    total_budget_spent = serializers.DecimalField(max_digits=12, decimal_places=2)
    annual_budget = serializers.DecimalField(max_digits=12, decimal_places=2)
    campaign_performance = serializers.DictField()
    monthly_spending = serializers.DictField()


# ============================================================================
# Nested Serializers for Complex Operations
# ============================================================================

class AgencyWithBrandsSerializer(AgencySerializer):
    """Agency serializer with nested brand creation.
    
    Allows creating an agency with multiple brands in a single request.
    """
    
    brands = BrandSerializer(many=True, required=False)
    
    class Meta(AgencySerializer.Meta):
        fields = AgencySerializer.Meta.fields + ['brands']
    
    def create(self, validated_data):
        """Create agency with nested brands."""
        brands_data = validated_data.pop('brands', [])
        agency = Agency.objects.create(**validated_data)
        
        for brand_data in brands_data:
            brand_data['agency'] = agency
            Brand.objects.create(**brand_data)
        
        return agency
    
    def update(self, instance, validated_data):
        """Update agency and handle nested brands."""
        brands_data = validated_data.pop('brands', [])
        
        # Update agency fields
        for attr, value in validated_data.items():
            setattr(instance, attr, value)
        instance.save()
        
        # Handle brands update (this is a simplified version)
        # In production, you might want more sophisticated handling
        for brand_data in brands_data:
            brand_id = brand_data.get('id')
            if brand_id:
                # Update existing brand
                brand = Brand.objects.get(id=brand_id, agency=instance)
                for attr, value in brand_data.items():
                    if attr != 'id':
                        setattr(brand, attr, value)
                brand.save()
            else:
                # Create new brand
                brand_data['agency'] = instance
                Brand.objects.create(**brand_data)
        
        return instance


class BulkUserAdvertiserSerializer(serializers.Serializer):
    """Serializer for bulk user-advertiser relationship operations.
    
    Allows creating multiple user-brand relationships at once.
    """
    
    users = serializers.ListField(
        child=serializers.IntegerField(),
        help_text="List of user IDs"
    )
    
    brands = serializers.ListField(
        child=serializers.IntegerField(),
        help_text="List of brand IDs"
    )
    
    role = serializers.ChoiceField(
        choices=UserAdvertiser.ROLE_CHOICES,
        default='viewer'
    )
    
    permissions = serializers.JSONField(
        default=dict,
        help_text="Permissions object"
    )
    
    def validate_users(self, value):
        """Validate that all user IDs exist."""
        existing_users = User.objects.filter(id__in=value).values_list('id', flat=True)
        missing_users = set(value) - set(existing_users)
        
        if missing_users:
            raise serializers.ValidationError(
                f"Users with IDs {list(missing_users)} do not exist."
            )
        
        return value
    
    def validate_brands(self, value):
        """Validate that all brand IDs exist."""
        existing_brands = Brand.objects.filter(id__in=value).values_list('id', flat=True)
        missing_brands = set(value) - set(existing_brands)
        
        if missing_brands:
            raise serializers.ValidationError(
                f"Brands with IDs {list(missing_brands)} do not exist."
            )
        
        return value
    
    def create_relationships(self):
        """Create user-advertiser relationships in bulk."""
        validated_data = self.validated_data
        users = validated_data['users']
        brands = validated_data['brands']
        role = validated_data['role']
        permissions = validated_data['permissions']
        
        relationships = []
        
        for user_id in users:
            for brand_id in brands:
                # Check if relationship already exists
                if not UserAdvertiser.objects.filter(
                    user_id=user_id, 
                    brand_id=brand_id
                ).exists():
                    relationships.append(
                        UserAdvertiser(
                            user_id=user_id,
                            brand_id=brand_id,
                            role=role,
                            permissions=permissions
                        )
                    )
        
        # Bulk create relationships
        created_relationships = UserAdvertiser.objects.bulk_create(relationships)
        
        return {
            'created_count': len(created_relationships),
            'relationships': UserAdvertiserSerializer(
                created_relationships, 
                many=True
            ).data
        }