# -*- coding: utf-8 -*-
"""
Advertisers App Serializers

This module contains all serializer classes for the Advertisers application.
It provides comprehensive data serialization and validation for all models
using Django REST Framework.
"""

from decimal import Decimal
from django.contrib.auth import get_user_model
from django.utils.translation import gettext_lazy as _
from django.core.validators import validate_email
from rest_framework import serializers
from rest_framework.validators import UniqueValidator, UniqueTogetherValidator

from .models import (
    BrandCategory,
    Agency,
    Advertiser,
    Brand,
    AdvertiserContact,
    AgencyUser,
    AdvertiserBilling
)

# Get the user model
User = get_user_model()


class BrandCategorySerializer(serializers.ModelSerializer):
    """
    Serializer for brand categories with basic information.
    """
    
    # Read-only fields
    brands_count = serializers.IntegerField(read_only=True)
    full_path = serializers.CharField(read_only=True)
    
    # Nested parent information
    parent_name = serializers.CharField(source='parent.name', read_only=True)
    
    class Meta:
        model = BrandCategory
        fields = [
            'id', 'name', 'parent', 'parent_name', 'description',
            'order', 'is_active', 'full_path', 'brands_count',
            'created_at', 'updated_at'
        ]
        read_only_fields = ['created_at', 'updated_at']
    
    def validate_parent(self, value):
        """
        Validate that parent category doesn't create circular reference.
        """
        if value and self.instance:
            # Check if setting this parent would create a circular reference
            current = value
            while current:
                if current == self.instance:
                    raise serializers.ValidationError(
                        _('Cannot set parent that would create a circular reference.')
                    )
                current = current.parent
        return value


class BrandCategoryDetailSerializer(BrandCategorySerializer):
    """
    Detailed serializer for brand categories with subcategories and brands.
    """
    
    # Nested subcategories
    subcategories = serializers.SerializerMethodField()
    
    # Recent brands in this category
    recent_brands = serializers.SerializerMethodField()
    
    class Meta(BrandCategorySerializer.Meta):
        fields = BrandCategorySerializer.Meta.fields + [
            'subcategories', 'recent_brands'
        ]
    
    def get_subcategories(self, obj):
        """
        Get active subcategories.
        """
        subcategories = obj.subcategories.filter(is_active=True)
        return BrandCategorySerializer(subcategories, many=True).data
    
    def get_recent_brands(self, obj):
        """
        Get recent brands in this category (limit 5).
        """
        from .serializers import BrandSerializer
        recent_brands = obj.brands.filter(is_active=True).order_by('-created_at')[:5]
        return BrandSerializer(recent_brands, many=True, context=self.context).data


class AgencySerializer(serializers.ModelSerializer):
    """
    Serializer for agencies with basic information.
    """
    
    # Read-only computed fields
    advertisers_count = serializers.IntegerField(read_only=True)
    users_count = serializers.IntegerField(read_only=True)
    
    # Creator information
    created_by_name = serializers.CharField(source='created_by.get_full_name', read_only=True)
    
    class Meta:
        model = Agency
        fields = [
            'id', 'name', 'code', 'email', 'phone', 'address',
            'city', 'country', 'website', 'description',
            'commission_rate', 'is_active', 'advertisers_count',
            'users_count', 'created_by', 'created_by_name',
            'created_at', 'updated_at'
        ]
        read_only_fields = ['created_by', 'created_at', 'updated_at']
        extra_kwargs = {
            'code': {
                'validators': [
                    UniqueValidator(
                        queryset=Agency.objects.all(),
                        message=_('Agency with this code already exists.')
                    )
                ]
            },
            'email': {
                'validators': [validate_email]
            }
        }
    
    def validate_commission_rate(self, value):
        """
        Validate commission rate is within reasonable bounds.
        """
        if value < Decimal('0.00') or value > Decimal('100.00'):
            raise serializers.ValidationError(
                _('Commission rate must be between 0% and 100%.')
            )
        return value
    
    def validate_code(self, value):
        """
        Validate and format agency code.
        """
        if value:
            value = value.upper().strip()
            if len(value) < 2:
                raise serializers.ValidationError(
                    _('Agency code must be at least 2 characters long.')
                )
        return value


class AgencyDetailSerializer(AgencySerializer):
    """
    Detailed serializer for agencies with related data.
    """
    
    # Statistics
    total_brands = serializers.SerializerMethodField()
    active_campaigns_count = serializers.SerializerMethodField()
    
    # Recent advertisers
    recent_advertisers = serializers.SerializerMethodField()
    
    class Meta(AgencySerializer.Meta):
        fields = AgencySerializer.Meta.fields + [
            'total_brands', 'active_campaigns_count', 'recent_advertisers'
        ]
    
    def get_total_brands(self, obj):
        """
        Get total number of brands managed by this agency.
        """
        return obj.total_brands
    
    def get_active_campaigns_count(self, obj):
        """
        Get number of active campaigns managed by this agency.
        """
        return obj.active_campaigns_count
    
    def get_recent_advertisers(self, obj):
        """
        Get recent advertisers managed by this agency (limit 5).
        """
        recent_advertisers = obj.advertisers.filter(is_active=True).order_by('-created_at')[:5]
        return AdvertiserSerializer(recent_advertisers, many=True, context=self.context).data


class AdvertiserSerializer(serializers.ModelSerializer):
    """
    Serializer for advertisers with basic information.
    """
    
    # Read-only computed fields
    brands_count = serializers.IntegerField(read_only=True)
    contacts_count = serializers.IntegerField(read_only=True)
    
    # Agency information
    agency_name = serializers.CharField(source='agency.name', read_only=True)
    
    # Creator information
    created_by_name = serializers.CharField(source='created_by.get_full_name', read_only=True)
    
    # Computed properties
    is_agency_managed = serializers.BooleanField(read_only=True)
    total_spend = serializers.SerializerMethodField()
    
    class Meta:
        model = Advertiser
        fields = [
            'id', 'name', 'code', 'advertiser_type', 'agency',
            'agency_name', 'email', 'phone', 'address', 'city',
            'country', 'website', 'industry', 'description',
            'credit_limit', 'is_active', 'brands_count',
            'contacts_count', 'is_agency_managed', 'total_spend',
            'created_by', 'created_by_name', 'created_at', 'updated_at'
        ]
        read_only_fields = ['created_by', 'created_at', 'updated_at']
        extra_kwargs = {
            'code': {
                'validators': [
                    UniqueValidator(
                        queryset=Advertiser.objects.all(),
                        message=_('Advertiser with this code already exists.')
                    )
                ]
            },
            'email': {
                'validators': [validate_email]
            }
        }
    
    def get_total_spend(self, obj):
        """
        Get total spend for this advertiser.
        """
        return obj.total_spend
    
    def validate(self, data):
        """
        Validate advertiser data based on type.
        """
        advertiser_type = data.get('advertiser_type')
        agency = data.get('agency')
        
        # Agency-managed advertisers must have an agency
        if advertiser_type == 'agency_managed' and not agency:
            raise serializers.ValidationError({
                'agency': _('Agency-managed advertisers must have an associated agency.')
            })
        
        # Individual advertisers should not have an agency
        if advertiser_type == 'individual' and agency:
            raise serializers.ValidationError({
                'agency': _('Individual advertisers should not have an associated agency.')
            })
        
        return data
    
    def validate_code(self, value):
        """
        Validate and format advertiser code.
        """
        if value:
            value = value.upper().strip()
            if len(value) < 2:
                raise serializers.ValidationError(
                    _('Advertiser code must be at least 2 characters long.')
                )
        return value
    
    def validate_credit_limit(self, value):
        """
        Validate credit limit is not negative.
        """
        if value < Decimal('0.00'):
            raise serializers.ValidationError(
                _('Credit limit cannot be negative.')
            )
        return value


class AdvertiserDetailSerializer(AdvertiserSerializer):
    """
    Detailed serializer for advertisers with related data.
    """
    
    # Statistics
    active_campaigns_count = serializers.SerializerMethodField()
    
    # Related data
    recent_brands = serializers.SerializerMethodField()
    primary_contact = serializers.SerializerMethodField()
    
    # Billing information
    billing_summary = serializers.SerializerMethodField()
    
    class Meta(AdvertiserSerializer.Meta):
        fields = AdvertiserSerializer.Meta.fields + [
            'active_campaigns_count', 'recent_brands',
            'primary_contact', 'billing_summary'
        ]
    
    def get_active_campaigns_count(self, obj):
        """
        Get number of active campaigns for this advertiser.
        """
        return obj.active_campaigns_count
    
    def get_recent_brands(self, obj):
        """
        Get recent brands for this advertiser (limit 5).
        """
        recent_brands = obj.brands.filter(is_active=True).order_by('-created_at')[:5]
        return BrandSerializer(recent_brands, many=True, context=self.context).data
    
    def get_primary_contact(self, obj):
        """
        Get primary contact for this advertiser.
        """
        try:
            primary_contact = obj.contacts.filter(
                contact_type='primary', is_active=True
            ).first()
            if primary_contact:
                return AdvertiserContactSerializer(primary_contact, context=self.context).data
        except Exception:
            pass
        return None
    
    def get_billing_summary(self, obj):
        """
        Get billing summary for this advertiser.
        """
        try:
            billing = obj.billing_info
            return {
                'payment_method': billing.payment_method,
                'billing_cycle': billing.billing_cycle,
                'credit_limit': billing.credit_limit,
                'current_balance': billing.current_balance,
                'available_credit': billing.available_credit,
                'is_over_limit': billing.is_over_limit
            }
        except AdvertiserBilling.DoesNotExist:
            return None


class BrandSerializer(serializers.ModelSerializer):
    """
    Serializer for brands with basic information.
    """
    
    # Advertiser information
    advertiser_name = serializers.CharField(source='advertiser.name', read_only=True)
    
    # Category information
    category_name = serializers.CharField(source='category.name', read_only=True)
    
    # Statistics
    campaigns_count = serializers.SerializerMethodField()
    active_campaigns_count = serializers.SerializerMethodField()
    
    class Meta:
        model = Brand
        fields = [
            'id', 'name', 'code', 'advertiser', 'advertiser_name',
            'category', 'category_name', 'description', 'website',
            'logo', 'primary_color', 'secondary_color', 'is_active',
            'campaigns_count', 'active_campaigns_count',
            'created_at', 'updated_at'
        ]
        read_only_fields = ['created_at', 'updated_at']
        validators = [
            UniqueTogetherValidator(
                queryset=Brand.objects.all(),
                fields=['advertiser', 'code'],
                message=_('Brand with this code already exists for this advertiser.')
            )
        ]
    
    def get_campaigns_count(self, obj):
        """
        Get total number of campaigns for this brand.
        """
        return obj.campaigns_count
    
    def get_active_campaigns_count(self, obj):
        """
        Get number of active campaigns for this brand.
        """
        return obj.active_campaigns_count
    
    def validate_code(self, value):
        """
        Validate and format brand code.
        """
        if value:
            value = value.upper().strip()
            if len(value) < 2:
                raise serializers.ValidationError(
                    _('Brand code must be at least 2 characters long.')
                )
        return value
    
    def validate_primary_color(self, value):
        """
        Validate primary color format.
        """
        if value and not value.startswith('#'):
            value = f'#{value}'
        return value
    
    def validate_secondary_color(self, value):
        """
        Validate secondary color format.
        """
        if value and not value.startswith('#'):
            value = f'#{value}'
        return value


class BrandDetailSerializer(BrandSerializer):
    """
    Detailed serializer for brands with campaign information.
    """
    
    # Recent campaigns
    recent_campaigns = serializers.SerializerMethodField()
    
    # Full advertiser information
    advertiser_details = serializers.SerializerMethodField()
    
    class Meta(BrandSerializer.Meta):
        fields = BrandSerializer.Meta.fields + [
            'recent_campaigns', 'advertiser_details'
        ]
    
    def get_recent_campaigns(self, obj):
        """
        Get recent campaigns for this brand (limit 5).
        """
        try:
            from apps.campaigns.models import Campaign
            from apps.campaigns.serializers import CampaignSerializer
            
            recent_campaigns = Campaign.objects.filter(
                brand=obj
            ).order_by('-created_at')[:5]
            
            return CampaignSerializer(
                recent_campaigns, many=True, context=self.context
            ).data
        except ImportError:
            return []
    
    def get_advertiser_details(self, obj):
        """
        Get basic advertiser information.
        """
        return {
            'id': obj.advertiser.id,
            'name': obj.advertiser.name,
            'code': obj.advertiser.code,
            'advertiser_type': obj.advertiser.advertiser_type,
            'is_agency_managed': obj.advertiser.is_agency_managed,
            'agency_name': obj.advertiser.agency.name if obj.advertiser.agency else None
        }


class AdvertiserContactSerializer(serializers.ModelSerializer):
    """
    Serializer for advertiser contacts.
    """
    
    # Advertiser information
    advertiser_name = serializers.CharField(source='advertiser.name', read_only=True)
    
    # Computed fields
    full_name = serializers.CharField(read_only=True)
    
    class Meta:
        model = AdvertiserContact
        fields = [
            'id', 'advertiser', 'advertiser_name', 'contact_type',
            'first_name', 'last_name', 'full_name', 'title',
            'email', 'phone', 'mobile', 'is_active',
            'created_at', 'updated_at'
        ]
        read_only_fields = ['created_at', 'updated_at']
        extra_kwargs = {
            'email': {
                'validators': [validate_email]
            }
        }
    
    def validate_email(self, value):
        """
        Validate email format and uniqueness within advertiser.
        """
        if value:
            advertiser = self.initial_data.get('advertiser') or (
                self.instance.advertiser if self.instance else None
            )
            
            if advertiser:
                # Check for duplicate emails within the same advertiser
                existing_contacts = AdvertiserContact.objects.filter(
                    advertiser=advertiser,
                    email=value,
                    is_active=True
                )
                
                if self.instance:
                    existing_contacts = existing_contacts.exclude(id=self.instance.id)
                
                if existing_contacts.exists():
                    raise serializers.ValidationError(
                        _('A contact with this email already exists for this advertiser.')
                    )
        
        return value


class AgencyUserSerializer(serializers.ModelSerializer):
    """
    Serializer for agency users.
    """
    
    # User information
    user_full_name = serializers.CharField(source='user.get_full_name', read_only=True)
    user_email = serializers.CharField(source='user.email', read_only=True)
    
    # Agency information
    agency_name = serializers.CharField(source='agency.name', read_only=True)
    
    # Permission summary
    permissions_summary = serializers.SerializerMethodField()
    
    class Meta:
        model = AgencyUser
        fields = [
            'id', 'user', 'user_full_name', 'user_email',
            'agency', 'agency_name', 'role', 'can_create_campaigns',
            'can_manage_advertisers', 'can_view_reports',
            'can_manage_billing', 'is_active', 'joined_at',
            'permissions_summary', 'created_at', 'updated_at'
        ]
        read_only_fields = ['joined_at', 'created_at', 'updated_at']
        validators = [
            UniqueTogetherValidator(
                queryset=AgencyUser.objects.all(),
                fields=['user', 'agency'],
                message=_('User is already associated with this agency.')
            )
        ]
    
    def get_permissions_summary(self, obj):
        """
        Get a summary of user permissions.
        """
        permissions = []
        if obj.can_create_campaigns:
            permissions.append('Campaigns')
        if obj.can_manage_advertisers:
            permissions.append('Advertisers')
        if obj.can_view_reports:
            permissions.append('Reports')
        if obj.can_manage_billing:
            permissions.append('Billing')
        
        return permissions if permissions else ['View Only']
    
    def validate(self, data):
        """
        Validate agency user data based on role.
        """
        role = data.get('role')
        
        # Auto-set permissions based on role
        if role == 'admin':
            data.update({
                'can_create_campaigns': True,
                'can_manage_advertisers': True,
                'can_view_reports': True,
                'can_manage_billing': True
            })
        elif role == 'manager':
            data.update({
                'can_create_campaigns': True,
                'can_manage_advertisers': True,
                'can_view_reports': True,
                'can_manage_billing': False
            })
        elif role == 'viewer':
            data.update({
                'can_create_campaigns': False,
                'can_manage_advertisers': False,
                'can_view_reports': True,
                'can_manage_billing': False
            })
        
        return data


class AdvertiserBillingSerializer(serializers.ModelSerializer):
    """
    Serializer for advertiser billing information.
    """
    
    # Advertiser information
    advertiser_name = serializers.CharField(source='advertiser.name', read_only=True)
    
    # Computed fields
    available_credit = serializers.DecimalField(
        max_digits=12, decimal_places=2, read_only=True
    )
    is_over_limit = serializers.BooleanField(read_only=True)
    
    class Meta:
        model = AdvertiserBilling
        fields = [
            'id', 'advertiser', 'advertiser_name', 'billing_name',
            'billing_address', 'tax_id', 'payment_method',
            'billing_cycle', 'credit_limit', 'current_balance',
            'available_credit', 'is_over_limit', 'is_active',
            'created_at', 'updated_at'
        ]
        read_only_fields = ['created_at', 'updated_at']
    
    def validate_credit_limit(self, value):
        """
        Validate credit limit is not negative.
        """
        if value < Decimal('0.00'):
            raise serializers.ValidationError(
                _('Credit limit cannot be negative.')
            )
        return value
    
    def validate_current_balance(self, value):
        """
        Validate current balance and warn if over limit.
        """
        credit_limit = self.initial_data.get('credit_limit') or (
            self.instance.credit_limit if self.instance else Decimal('0.00')
        )
        
        if value > credit_limit:
            # This is a warning, not an error - allow but notify
            pass
        
        return value
    
    def validate(self, data):
        """
        Validate billing data consistency.
        """
        credit_limit = data.get('credit_limit', Decimal('0.00'))
        current_balance = data.get('current_balance', Decimal('0.00'))
        
        # Check if advertiser already has billing info (for creation)
        advertiser = data.get('advertiser')
        if advertiser and not self.instance:
            if AdvertiserBilling.objects.filter(advertiser=advertiser).exists():
                raise serializers.ValidationError({
                    'advertiser': _('Billing information already exists for this advertiser.')
                })
        
        return data


# Nested serializers for related data
class NestedAgencySerializer(serializers.ModelSerializer):
    """
    Nested serializer for agency information in other serializers.
    """
    
    class Meta:
        model = Agency
        fields = ['id', 'name', 'code', 'commission_rate']


class NestedAdvertiserSerializer(serializers.ModelSerializer):
    """
    Nested serializer for advertiser information in other serializers.
    """
    
    agency = NestedAgencySerializer(read_only=True)
    
    class Meta:
        model = Advertiser
        fields = [
            'id', 'name', 'code', 'advertiser_type',
            'agency', 'is_agency_managed'
        ]


class NestedBrandSerializer(serializers.ModelSerializer):
    """
    Nested serializer for brand information in other serializers.
    """
    
    advertiser = NestedAdvertiserSerializer(read_only=True)
    category_name = serializers.CharField(source='category.name', read_only=True)
    
    class Meta:
        model = Brand
        fields = [
            'id', 'name', 'code', 'advertiser',
            'category_name', 'primary_color'
        ]