# -*- coding: utf-8 -*-
"""
Notifications Serializers

This module contains Django REST Framework serializers for the notifications app,
handling the conversion between model instances and JSON representations
for API endpoints.

Serializers:
    - NotificationTypeSerializer: Notification type serialization
    - NotificationSerializer: Notification serialization
    - NotificationPreferenceSerializer: User preference serialization
    - NotificationTemplateSerializer: Template serialization
    - NotificationStatsSerializer: Statistics serialization
    - NotificationCreateSerializer: Create notification serialization
    - BulkNotificationSerializer: Bulk notification serialization

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

import json
from datetime import datetime, timedelta
from rest_framework import serializers
from rest_framework.validators import UniqueValidator
from django.contrib.auth import get_user_model
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from django.core.exceptions import ValidationError as DjangoValidationError

from .models import (
    NotificationType,
    Notification,
    NotificationPreference,
    NotificationTemplate,
    NotificationQueue,
    NotificationHistory,
)

User = get_user_model()


class NotificationTypeSerializer(serializers.ModelSerializer):
    """
    Serializer for NotificationType model.
    
    This serializer handles the conversion of NotificationType
    instances to/from JSON for API endpoints.
    """
    
    notification_count = serializers.SerializerMethodField()
    
    class Meta:
        model = NotificationType
        fields = [
            'id',
            'name',
            'slug',
            'description',
            'icon',
            'color',
            'is_active',
            'can_be_disabled',
            'default_email_enabled',
            'default_in_app_enabled',
            'priority',
            'created_at',
            'updated_at',
            'notification_count',
        ]
        read_only_fields = ['id', 'slug', 'created_at', 'updated_at', 'notification_count']
    
    def get_notification_count(self, obj):
        """
        Get the count of notifications for this type.
        
        Args:
            obj: NotificationType instance
        
        Returns:
            int: Number of notifications
        """
        return obj.notifications.count()
    
    def validate_name(self, value):
        """
        Validate notification type name.
        
        Args:
            value: Name value
        
        Returns:
            str: Validated name
        
        Raises:
            serializers.ValidationError: If validation fails
        """
        if len(value.strip()) < 3:
            raise serializers.ValidationError(_('Name must be at least 3 characters long.'))
        
        return value.strip()
    
    def validate_priority(self, value):
        """
        Validate priority value.
        
        Args:
            value: Priority value
        
        Returns:
            int: Validated priority
        
        Raises:
            serializers.ValidationError: If validation fails
        """
        if value < 1 or value > 10:
            raise serializers.ValidationError(_('Priority must be between 1 and 10.'))
        
        return value


class NotificationSerializer(serializers.ModelSerializer):
    """
    Serializer for Notification model.
    
    This serializer handles the conversion of Notification
    instances to/from JSON for API endpoints.
    """
    
    recipient_name = serializers.CharField(source='recipient.get_full_name', read_only=True)
    recipient_email = serializers.EmailField(source='recipient.email', read_only=True)
    notification_type_name = serializers.CharField(source='notification_type.name', read_only=True)
    notification_type_icon = serializers.CharField(source='notification_type.icon', read_only=True)
    notification_type_color = serializers.CharField(source='notification_type.color', read_only=True)
    is_expired = serializers.SerializerMethodField()
    time_since_created = serializers.SerializerMethodField()
    
    class Meta:
        model = Notification
        fields = [
            'id',
            'recipient',
            'recipient_name',
            'recipient_email',
            'notification_type',
            'notification_type_name',
            'notification_type_icon',
            'notification_type_color',
            'title',
            'message',
            'action_url',
            'is_read',
            'is_archived',
            'read_at',
            'archived_at',
            'expires_at',
            'is_expired',
            'metadata',
            'created_at',
            'updated_at',
            'time_since_created',
        ]
        read_only_fields = [
            'id',
            'recipient_name',
            'recipient_email',
            'notification_type_name',
            'notification_type_icon',
            'notification_type_color',
            'is_expired',
            'read_at',
            'archived_at',
            'created_at',
            'updated_at',
            'time_since_created',
        ]
    
    def get_is_expired(self, obj):
        """
        Check if notification is expired.
        
        Args:
            obj: Notification instance
        
        Returns:
            bool: True if expired
        """
        return obj.is_expired
    
    def get_time_since_created(self, obj):
        """
        Get human-readable time since creation.
        
        Args:
            obj: Notification instance
        
        Returns:
            str: Time since creation
        """
        now = timezone.now()
        diff = now - obj.created_at
        
        if diff.days > 0:
            return f"{diff.days} day{'s' if diff.days > 1 else ''} ago"
        elif diff.seconds > 3600:
            hours = diff.seconds // 3600
            return f"{hours} hour{'s' if hours > 1 else ''} ago"
        elif diff.seconds > 60:
            minutes = diff.seconds // 60
            return f"{minutes} minute{'s' if minutes > 1 else ''} ago"
        else:
            return "Just now"
    
    def validate_expires_at(self, value):
        """
        Validate expiration date.
        
        Args:
            value: Expiration date
        
        Returns:
            datetime: Validated expiration date
        
        Raises:
            serializers.ValidationError: If validation fails
        """
        if value and value <= timezone.now():
            raise serializers.ValidationError(_('Expiration date must be in the future.'))
        
        return value
    
    def validate_metadata(self, value):
        """
        Validate metadata JSON.
        
        Args:
            value: Metadata value
        
        Returns:
            dict: Validated metadata
        
        Raises:
            serializers.ValidationError: If validation fails
        """
        if value and not isinstance(value, dict):
            raise serializers.ValidationError(_('Metadata must be a valid JSON object.'))
        
        return value or {}


class NotificationListSerializer(NotificationSerializer):
    """
    Simplified serializer for notification lists.
    
    This serializer provides a lighter version for list views
    with only essential fields.
    """
    
    class Meta(NotificationSerializer.Meta):
        fields = [
            'id',
            'notification_type_name',
            'notification_type_icon',
            'notification_type_color',
            'title',
            'is_read',
            'is_archived',
            'is_expired',
            'created_at',
            'time_since_created',
        ]


class NotificationPreferenceSerializer(serializers.ModelSerializer):
    """
    Serializer for NotificationPreference model.
    
    This serializer handles user notification preferences
    for API endpoints.
    """
    
    user_name = serializers.CharField(source='user.get_full_name', read_only=True)
    notification_type_name = serializers.CharField(source='notification_type.name', read_only=True)
    
    class Meta:
        model = NotificationPreference
        fields = [
            'id',
            'user',
            'user_name',
            'notification_type',
            'notification_type_name',
            'is_enabled',
            'email_enabled',
            'in_app_enabled',
            'quiet_hours_start',
            'quiet_hours_end',
            'timezone',
            'created_at',
            'updated_at',
        ]
        read_only_fields = ['id', 'user_name', 'notification_type_name', 'created_at', 'updated_at']
    
    def validate(self, data):
        """
        Validate preference data.
        
        Args:
            data: Preference data
        
        Returns:
            dict: Validated data
        
        Raises:
            serializers.ValidationError: If validation fails
        """
        quiet_start = data.get('quiet_hours_start')
        quiet_end = data.get('quiet_hours_end')
        
        # Validate quiet hours
        if quiet_start and not quiet_end:
            raise serializers.ValidationError({
                'quiet_hours_end': _('Please specify both start and end times for quiet hours.')
            })
        
        if quiet_end and not quiet_start:
            raise serializers.ValidationError({
                'quiet_hours_start': _('Please specify both start and end times for quiet hours.')
            })
        
        # Check if at least one delivery method is enabled
        if data.get('is_enabled'):
            if not data.get('email_enabled') and not data.get('in_app_enabled'):
                raise serializers.ValidationError({
                    'non_field_errors': [_('At least one delivery method must be enabled.')]
                })
        
        return data


class NotificationTemplateSerializer(serializers.ModelSerializer):
    """
    Serializer for NotificationTemplate model.
    
    This serializer handles notification templates
    for API endpoints.
    """
    
    usage_count = serializers.SerializerMethodField()
    
    class Meta:
        model = NotificationTemplate
        fields = [
            'id',
            'name',
            'template_type',
            'description',
            'subject',
            'html_content',
            'text_content',
            'variables',
            'is_active',
            'usage_count',
            'created_at',
            'updated_at',
        ]
        read_only_fields = ['id', 'usage_count', 'created_at', 'updated_at']
    
    def get_usage_count(self, obj):
        """
        Get template usage count.
        
        Args:
            obj: NotificationTemplate instance
        
        Returns:
            int: Usage count
        """
        # This would require tracking template usage
        # For now, return 0 or implement based on your needs
        return 0
    
    def validate_variables(self, value):
        """
        Validate variables JSON.
        
        Args:
            value: Variables value
        
        Returns:
            dict: Validated variables
        
        Raises:
            serializers.ValidationError: If validation fails
        """
        if value and not isinstance(value, dict):
            raise serializers.ValidationError(_('Variables must be a valid JSON object.'))
        
        return value or {}
    
    def validate(self, data):
        """
        Validate template data.
        
        Args:
            data: Template data
        
        Returns:
            dict: Validated data
        
        Raises:
            serializers.ValidationError: If validation fails
        """
        template_type = data.get('template_type')
        html_content = data.get('html_content')
        text_content = data.get('text_content')
        subject = data.get('subject')
        
        # Validate content based on template type
        if template_type == 'email':
            if not subject:
                raise serializers.ValidationError({
                    'subject': _('Email templates must have a subject.')
                })
            if not html_content and not text_content:
                raise serializers.ValidationError({
                    'non_field_errors': [_('Email templates must have either HTML or text content.')]
                })
        
        elif template_type == 'in_app':
            if not html_content and not text_content:
                raise serializers.ValidationError({
                    'non_field_errors': [_('In-app templates must have content.')]
                })
        
        return data


class NotificationQueueSerializer(serializers.ModelSerializer):
    """
    Serializer for NotificationQueue model.
    
    This serializer handles queued notifications
    for API endpoints.
    """
    
    notification_type_name = serializers.CharField(source='notification_type.name', read_only=True)
    recipient_count = serializers.SerializerMethodField()
    
    class Meta:
        model = NotificationQueue
        fields = [
            'id',
            'notification_type',
            'notification_type_name',
            'title',
            'message',
            'recipients',
            'recipient_count',
            'scheduled_at',
            'status',
            'retry_count',
            'max_retries',
            'error_message',
            'metadata',
            'created_at',
            'updated_at',
        ]
        read_only_fields = [
            'id',
            'notification_type_name',
            'recipient_count',
            'status',
            'retry_count',
            'error_message',
            'created_at',
            'updated_at',
        ]
    
    def get_recipient_count(self, obj):
        """
        Get recipient count.
        
        Args:
            obj: NotificationQueue instance
        
        Returns:
            int: Number of recipients
        """
        return len(obj.recipients) if obj.recipients else 0
    
    def validate_scheduled_at(self, value):
        """
        Validate scheduled time.
        
        Args:
            value: Scheduled time
        
        Returns:
            datetime: Validated scheduled time
        
        Raises:
            serializers.ValidationError: If validation fails
        """
        if value and value <= timezone.now():
            raise serializers.ValidationError(_('Scheduled time must be in the future.'))
        
        return value
    
    def validate_recipients(self, value):
        """
        Validate recipients list.
        
        Args:
            value: Recipients list
        
        Returns:
            list: Validated recipients
        
        Raises:
            serializers.ValidationError: If validation fails
        """
        if not value or not isinstance(value, list):
            raise serializers.ValidationError(_('Recipients must be a non-empty list.'))
        
        if len(value) > 1000:
            raise serializers.ValidationError(_('Cannot send to more than 1000 recipients at once.'))
        
        return value


class NotificationHistorySerializer(serializers.ModelSerializer):
    """
    Serializer for NotificationHistory model.
    
    This serializer handles notification delivery history
    for API endpoints.
    """
    
    notification_title = serializers.CharField(source='notification.title', read_only=True)
    recipient_name = serializers.CharField(source='notification.recipient.get_full_name', read_only=True)
    
    class Meta:
        model = NotificationHistory
        fields = [
            'id',
            'notification',
            'notification_title',
            'recipient_name',
            'delivery_method',
            'status',
            'attempted_at',
            'delivered_at',
            'error_message',
            'metadata',
        ]
        read_only_fields = [
            'id',
            'notification_title',
            'recipient_name',
            'attempted_at',
            'delivered_at',
            'error_message',
        ]


class NotificationStatsSerializer(serializers.Serializer):
    """
    Serializer for notification statistics.
    
    This serializer handles notification statistics
    for dashboard and analytics endpoints.
    """
    
    total_notifications = serializers.IntegerField(read_only=True)
    unread_notifications = serializers.IntegerField(read_only=True)
    read_notifications = serializers.IntegerField(read_only=True)
    archived_notifications = serializers.IntegerField(read_only=True)
    expired_notifications = serializers.IntegerField(read_only=True)
    
    notifications_today = serializers.IntegerField(read_only=True)
    notifications_this_week = serializers.IntegerField(read_only=True)
    notifications_this_month = serializers.IntegerField(read_only=True)
    
    by_type = serializers.DictField(read_only=True)
    by_status = serializers.DictField(read_only=True)
    recent_activity = serializers.ListField(read_only=True)
    
    class Meta:
        fields = [
            'total_notifications',
            'unread_notifications',
            'read_notifications',
            'archived_notifications',
            'expired_notifications',
            'notifications_today',
            'notifications_this_week',
            'notifications_this_month',
            'by_type',
            'by_status',
            'recent_activity',
        ]


class NotificationCreateSerializer(serializers.ModelSerializer):
    """
    Serializer for creating notifications.
    
    This serializer handles notification creation
    with validation and processing.
    """
    
    send_immediately = serializers.BooleanField(default=True, write_only=True)
    
    class Meta:
        model = Notification
        fields = [
            'recipient',
            'notification_type',
            'title',
            'message',
            'action_url',
            'expires_at',
            'metadata',
            'send_immediately',
        ]
    
    def validate_recipient(self, value):
        """
        Validate recipient.
        
        Args:
            value: Recipient user
        
        Returns:
            User: Validated recipient
        
        Raises:
            serializers.ValidationError: If validation fails
        """
        if not value.is_active:
            raise serializers.ValidationError(_('Cannot send notification to inactive user.'))
        
        return value
    
    def create(self, validated_data):
        """
        Create notification.
        
        Args:
            validated_data: Validated data
        
        Returns:
            Notification: Created notification
        """
        send_immediately = validated_data.pop('send_immediately', True)
        notification = super().create(validated_data)
        
        if send_immediately:
            # Import here to avoid circular imports
            from .tasks import send_notification_task
            send_notification_task.delay(notification.id)
        
        return notification


class BulkNotificationSerializer(serializers.Serializer):
    """
    Serializer for bulk notification creation.
    
    This serializer handles creating notifications
    for multiple recipients at once.
    """
    
    recipients = serializers.ListField(
        child=serializers.IntegerField(),
        min_length=1,
        max_length=1000
    )
    
    notification_type = serializers.PrimaryKeyRelatedField(
        queryset=NotificationType.objects.active()
    )
    
    title = serializers.CharField(max_length=255)
    message = serializers.CharField()
    action_url = serializers.URLField(required=False, allow_blank=True)
    expires_at = serializers.DateTimeField(required=False)
    metadata = serializers.DictField(required=False)
    send_immediately = serializers.BooleanField(default=True)
    
    def validate_recipients(self, value):
        """
        Validate recipients list.
        
        Args:
            value: List of recipient IDs
        
        Returns:
            list: Validated recipient IDs
        
        Raises:
            serializers.ValidationError: If validation fails
        """
        # Check if all recipients exist and are active
        existing_users = User.objects.filter(
            id__in=value,
            is_active=True
        ).values_list('id', flat=True)
        
        invalid_ids = set(value) - set(existing_users)
        if invalid_ids:
            raise serializers.ValidationError(
                f"Invalid or inactive user IDs: {', '.join(map(str, invalid_ids))}"
            )
        
        return value
    
    def validate_expires_at(self, value):
        """
        Validate expiration date.
        
        Args:
            value: Expiration date
        
        Returns:
            datetime: Validated expiration date
        
        Raises:
            serializers.ValidationError: If validation fails
        """
        if value and value <= timezone.now():
            raise serializers.ValidationError(_('Expiration date must be in the future.'))
        
        return value
    
    def create(self, validated_data):
        """
        Create bulk notifications.
        
        Args:
            validated_data: Validated data
        
        Returns:
            dict: Creation result
        """
        recipients = validated_data.pop('recipients')
        send_immediately = validated_data.pop('send_immediately', True)
        
        # Create notifications for all recipients
        notifications = []
        for recipient_id in recipients:
            notification_data = validated_data.copy()
            notification_data['recipient_id'] = recipient_id
            notification = Notification.objects.create(**notification_data)
            notifications.append(notification)
        
        if send_immediately:
            # Import here to avoid circular imports
            from .tasks import send_bulk_notifications_task
            notification_ids = [n.id for n in notifications]
            send_bulk_notifications_task.delay(notification_ids)
        
        return {
            'created_count': len(notifications),
            'notification_ids': [n.id for n in notifications],
            'send_immediately': send_immediately,
        }


class NotificationActionSerializer(serializers.Serializer):
    """
    Serializer for notification actions.
    
    This serializer handles bulk actions on notifications
    like mark as read, archive, delete, etc.
    """
    
    notification_ids = serializers.ListField(
        child=serializers.IntegerField(),
        min_length=1
    )
    
    action = serializers.ChoiceField(
        choices=[
            ('mark_read', _('Mark as Read')),
            ('mark_unread', _('Mark as Unread')),
            ('archive', _('Archive')),
            ('unarchive', _('Unarchive')),
            ('delete', _('Delete')),
        ]
    )
    
    def validate_notification_ids(self, value):
        """
        Validate notification IDs.
        
        Args:
            value: List of notification IDs
        
        Returns:
            list: Validated notification IDs
        
        Raises:
            serializers.ValidationError: If validation fails
        """
        # Check if notifications exist and belong to the user
        user = self.context['request'].user
        existing_notifications = Notification.objects.filter(
            id__in=value,
            recipient=user
        ).values_list('id', flat=True)
        
        invalid_ids = set(value) - set(existing_notifications)
        if invalid_ids:
            raise serializers.ValidationError(
                f"Invalid notification IDs: {', '.join(map(str, invalid_ids))}"
            )
        
        return value
    
    def save(self):
        """
        Execute the bulk action.
        
        Returns:
            dict: Action result
        """
        notification_ids = self.validated_data['notification_ids']
        action = self.validated_data['action']
        user = self.context['request'].user
        
        notifications = Notification.objects.filter(
            id__in=notification_ids,
            recipient=user
        )
        
        updated_count = 0
        
        if action == 'mark_read':
            updated_count = notifications.filter(is_read=False).update(
                is_read=True,
                read_at=timezone.now()
            )
        
        elif action == 'mark_unread':
            updated_count = notifications.filter(is_read=True).update(
                is_read=False,
                read_at=None
            )
        
        elif action == 'archive':
            updated_count = notifications.filter(is_archived=False).update(
                is_archived=True,
                archived_at=timezone.now()
            )
        
        elif action == 'unarchive':
            updated_count = notifications.filter(is_archived=True).update(
                is_archived=False,
                archived_at=None
            )
        
        elif action == 'delete':
            updated_count = notifications.count()
            notifications.delete()
        
        return {
            'action': action,
            'updated_count': updated_count,
            'notification_ids': notification_ids,
        }