from rest_framework import serializers
from django.utils import timezone
from .models import BroadcastMessage, MessageRecipient, PuckEmailTemplate, CustomEmailTemplate
from .email_types import EmailType
from .email_tags import validate_tags, get_tag_info_for_email_type


class MessageRecipientSerializer(serializers.ModelSerializer):
    """Serializer for message delivery tracking."""
    user_email = serializers.CharField(source='user.email', read_only=True)
    user_name = serializers.SerializerMethodField()

    class Meta:
        model = MessageRecipient
        fields = [
            'id', 'user', 'user_email', 'user_name',
            'delivery_status', 'delivered_at',
            'is_read', 'read_at', 'error_message'
        ]
        read_only_fields = fields

    def get_user_name(self, obj):
        return obj.user.get_full_name() or obj.user.username


class BroadcastMessageListSerializer(serializers.ModelSerializer):
    """Serializer for listing broadcast messages."""
    created_by = serializers.SerializerMethodField()
    created_by_name = serializers.SerializerMethodField()
    target_roles = serializers.SerializerMethodField()
    target_users = serializers.SerializerMethodField()
    delivery_method = serializers.SerializerMethodField()
    status = serializers.SerializerMethodField()

    class Meta:
        model = BroadcastMessage
        fields = [
            'id', 'subject', 'body', 'status', 'delivery_method',
            'created_by', 'created_by_name',
            'target_roles', 'target_users',
            'total_recipients', 'delivered_count', 'read_count',
            'created_at', 'sent_at', 'scheduled_at'
        ]
        read_only_fields = fields

    def get_created_by(self, obj):
        """Return sender ID as string."""
        if obj.sender:
            return str(obj.sender.id)
        return None

    def get_created_by_name(self, obj):
        """Return sender's full name."""
        if obj.sender:
            return obj.sender.get_full_name() or obj.sender.username
        return 'Unknown'

    def get_target_roles(self, obj):
        """Return array of targeted role strings."""
        roles = []
        if obj.target_owners:
            roles.append('owner')
        if obj.target_managers:
            roles.append('manager')
        if obj.target_staff:
            roles.append('staff')
        if obj.target_customers:
            roles.append('customer')
        return roles

    def get_target_users(self, obj):
        """Return array of individual recipient IDs as strings."""
        return [str(user.id) for user in obj.individual_recipients.all()]

    def get_delivery_method(self, obj):
        """Return delivery method in uppercase format (IN_APP, EMAIL, etc.)."""
        return obj.delivery_method.upper()

    def get_status(self, obj):
        """Return status in uppercase format (SENT, DRAFT, etc.)."""
        return obj.status.upper()


class BroadcastMessageDetailSerializer(serializers.ModelSerializer):
    """Serializer for broadcast message detail view."""
    sender_name = serializers.SerializerMethodField()
    target_description = serializers.SerializerMethodField()
    recipients = MessageRecipientSerializer(many=True, read_only=True)
    individual_recipient_ids = serializers.ListField(
        child=serializers.IntegerField(),
        write_only=True,
        required=False
    )

    class Meta:
        model = BroadcastMessage
        fields = [
            'id', 'subject', 'body', 'status', 'delivery_method',
            'target_owners', 'target_managers', 'target_staff', 'target_customers',
            'individual_recipient_ids',
            'sender_name', 'target_description',
            'total_recipients', 'delivered_count', 'failed_count', 'read_count',
            'created_at', 'updated_at', 'sent_at', 'scheduled_at',
            'recipients'
        ]
        read_only_fields = [
            'id', 'sender_name', 'target_description',
            'total_recipients', 'delivered_count', 'failed_count', 'read_count',
            'created_at', 'updated_at', 'sent_at', 'recipients'
        ]

    def get_sender_name(self, obj):
        if obj.sender:
            return obj.sender.get_full_name() or obj.sender.username
        return 'Unknown'

    def get_target_description(self, obj):
        return obj.get_target_description()

    def validate(self, data):
        """Ensure at least one target is selected."""
        target_owners = data.get('target_owners', False)
        target_managers = data.get('target_managers', False)
        target_staff = data.get('target_staff', False)
        target_customers = data.get('target_customers', False)
        individual_recipients = data.get('individual_recipient_ids', [])

        if not any([target_owners, target_managers, target_staff, target_customers]) and not individual_recipients:
            raise serializers.ValidationError(
                "At least one target group or individual recipient must be selected."
            )
        return data


class BroadcastMessageCreateSerializer(serializers.ModelSerializer):
    """Serializer for creating broadcast messages - accepts frontend format."""
    # Frontend sends these fields
    target_roles = serializers.ListField(
        child=serializers.CharField(),
        write_only=True,
        required=False,
        default=list
    )
    target_users = serializers.ListField(
        child=serializers.CharField(),  # Frontend sends as strings
        write_only=True,
        required=False,
        default=list
    )
    delivery_method = serializers.CharField(required=False, default='in_app')  # Override to accept any case

    # Internal fields (not exposed to frontend)
    individual_recipient_ids = serializers.ListField(
        child=serializers.IntegerField(),
        write_only=True,
        required=False,
        default=list
    )
    send_immediately = serializers.BooleanField(write_only=True, default=True)

    class Meta:
        model = BroadcastMessage
        fields = [
            'subject', 'body', 'delivery_method',
            'target_roles', 'target_users',  # Frontend format
            'target_owners', 'target_managers', 'target_staff', 'target_customers',  # Legacy
            'individual_recipient_ids', 'scheduled_at', 'send_immediately'
        ]
        extra_kwargs = {
            'delivery_method': {'required': False}
        }

    def validate_target_roles(self, value):
        """Validate that all role names are valid."""
        valid_roles = {'owner', 'manager', 'staff', 'customer'}
        invalid_roles = set(value) - valid_roles
        if invalid_roles:
            raise serializers.ValidationError(
                f"Invalid role(s): {', '.join(invalid_roles)}. "
                f"Valid roles are: {', '.join(valid_roles)}"
            )
        return value

    def validate_delivery_method(self, value):
        """Accept uppercase delivery method and convert to lowercase."""
        value_lower = value.lower()
        valid_methods = ['in_app', 'email', 'sms', 'all']
        if value_lower not in valid_methods:
            raise serializers.ValidationError(
                f"Invalid delivery method. Valid options: {', '.join(valid_methods)}"
            )
        return value_lower

    def validate(self, data):
        """
        Convert frontend format to backend format and validate at least one target is selected.
        """
        # Convert target_roles array to boolean fields
        target_roles = data.pop('target_roles', [])
        data['target_owners'] = 'owner' in target_roles
        data['target_managers'] = 'manager' in target_roles
        data['target_staff'] = 'staff' in target_roles
        data['target_customers'] = 'customer' in target_roles

        # Convert target_users to individual_recipient_ids (string IDs to integers)
        target_users = data.pop('target_users', [])
        if target_users:
            try:
                data['individual_recipient_ids'] = [int(uid) for uid in target_users]
            except (ValueError, TypeError):
                raise serializers.ValidationError({
                    'target_users': 'All user IDs must be valid integers'
                })

        # Validate at least one target is selected
        target_owners = data.get('target_owners', False)
        target_managers = data.get('target_managers', False)
        target_staff = data.get('target_staff', False)
        target_customers = data.get('target_customers', False)
        individual_recipients = data.get('individual_recipient_ids', [])

        if not any([target_owners, target_managers, target_staff, target_customers]) and not individual_recipients:
            raise serializers.ValidationError(
                "At least one target group or individual recipient must be selected."
            )
        return data

    def create(self, validated_data):
        individual_recipient_ids = validated_data.pop('individual_recipient_ids', [])
        send_immediately = validated_data.pop('send_immediately', True)

        # Set status based on scheduling
        if validated_data.get('scheduled_at') and not send_immediately:
            validated_data['status'] = BroadcastMessage.Status.SCHEDULED
        else:
            validated_data['status'] = BroadcastMessage.Status.DRAFT

        message = BroadcastMessage.objects.create(**validated_data)

        # Add individual recipients
        if individual_recipient_ids:
            from smoothschedule.identity.users.models import User
            users = User.objects.filter(id__in=individual_recipient_ids)
            message.individual_recipients.set(users)

        return message


class InboxMessageSerializer(serializers.ModelSerializer):
    """Serializer for user's inbox (received messages)."""
    sender_name = serializers.SerializerMethodField()
    is_read = serializers.SerializerMethodField()
    read_at = serializers.SerializerMethodField()

    class Meta:
        model = BroadcastMessage
        fields = [
            'id', 'subject', 'body', 'sender_name',
            'is_read', 'read_at', 'sent_at', 'created_at'
        ]
        read_only_fields = fields

    def get_sender_name(self, obj):
        if obj.sender:
            return obj.sender.get_full_name() or obj.sender.username
        return 'System'

    def get_is_read(self, obj):
        """Get read status for the current user."""
        request = self.context.get('request')
        if request and request.user:
            recipient = obj.recipients.filter(user=request.user).first()
            if recipient:
                return recipient.is_read
        return False

    def get_read_at(self, obj):
        """Get read timestamp for the current user."""
        request = self.context.get('request')
        if request and request.user:
            recipient = obj.recipients.filter(user=request.user).first()
            if recipient:
                return recipient.read_at
        return None


# =============================================================================
# Puck Email Template Serializers
# =============================================================================

class PuckEmailTemplateListSerializer(serializers.ModelSerializer):
    """Serializer for listing email templates."""
    display_name = serializers.SerializerMethodField()
    description = serializers.SerializerMethodField()
    category = serializers.SerializerMethodField()

    class Meta:
        model = PuckEmailTemplate
        fields = [
            'id', 'email_type', 'display_name', 'description', 'category',
            'subject_template', 'is_active', 'is_customized',
            'created_at', 'updated_at'
        ]
        read_only_fields = fields

    def get_display_name(self, obj):
        return obj.get_email_type_display_name()

    def get_description(self, obj):
        return obj.get_email_type_description()

    def get_category(self, obj):
        try:
            return EmailType.get_category(EmailType(obj.email_type))
        except ValueError:
            return 'other'


class PuckEmailTemplateDetailSerializer(serializers.ModelSerializer):
    """Serializer for viewing/editing a single email template."""
    display_name = serializers.SerializerMethodField()
    description = serializers.SerializerMethodField()
    category = serializers.SerializerMethodField()
    available_tags = serializers.SerializerMethodField()

    class Meta:
        model = PuckEmailTemplate
        fields = [
            'id', 'email_type', 'display_name', 'description', 'category',
            'subject_template', 'puck_data',
            'is_active', 'is_customized',
            'available_tags',
            'created_at', 'updated_at'
        ]
        read_only_fields = [
            'id', 'email_type', 'display_name', 'description', 'category',
            'available_tags', 'created_at', 'updated_at'
        ]

    def get_display_name(self, obj):
        return obj.get_email_type_display_name()

    def get_description(self, obj):
        return obj.get_email_type_description()

    def get_category(self, obj):
        try:
            return EmailType.get_category(EmailType(obj.email_type))
        except ValueError:
            return 'other'

    def get_available_tags(self, obj):
        try:
            email_type = EmailType(obj.email_type)
            return get_tag_info_for_email_type(email_type)
        except ValueError:
            return []

    def validate(self, data):
        """Validate tags in subject and puck_data."""
        instance = self.instance
        if not instance:
            return data

        subject = data.get('subject_template', instance.subject_template)
        puck_data = data.get('puck_data', instance.puck_data)

        try:
            email_type = EmailType(instance.email_type)
        except ValueError:
            raise serializers.ValidationError({
                'email_type': f'Invalid email type: {instance.email_type}'
            })

        errors = validate_tags(subject, puck_data, email_type)
        if errors:
            raise serializers.ValidationError({'subject_template': errors})

        return data

    def update(self, instance, validated_data):
        """Mark template as customized when updated."""
        validated_data['is_customized'] = True
        return super().update(instance, validated_data)


class EmailTemplatePreviewSerializer(serializers.Serializer):
    """Serializer for previewing rendered email template."""
    context = serializers.DictField(
        child=serializers.CharField(allow_blank=True),
        required=False,
        default=dict,
        help_text="Tag values for preview rendering"
    )


class EmailTagSerializer(serializers.Serializer):
    """Serializer for tag information."""
    name = serializers.CharField()
    description = serializers.CharField()
    category = serializers.CharField()
    syntax = serializers.CharField()


# =============================================================================
# Custom Email Template Serializers (for plugins)
# =============================================================================

class CustomEmailTemplateListSerializer(serializers.ModelSerializer):
    """List serializer for custom email templates."""

    class Meta:
        model = CustomEmailTemplate
        fields = [
            'id',
            'slug',
            'name',
            'description',
            'is_active',
            'created_at',
            'updated_at',
        ]
        read_only_fields = ['id', 'created_at', 'updated_at']


class CustomEmailTemplateDetailSerializer(serializers.ModelSerializer):
    """Detail serializer for custom email templates with all fields."""
    available_tags = serializers.SerializerMethodField()

    class Meta:
        model = CustomEmailTemplate
        fields = [
            'id',
            'slug',
            'name',
            'description',
            'subject_template',
            'puck_data',
            'is_active',
            'available_tags',
            'created_at',
            'updated_at',
        ]
        read_only_fields = ['id', 'available_tags', 'created_at', 'updated_at']

    def get_available_tags(self, obj):
        """Return all available tags for custom templates."""
        from .email_tags import get_all_tag_info
        return get_all_tag_info()


class CustomEmailTemplateCreateSerializer(serializers.ModelSerializer):
    """Serializer for creating custom email templates."""

    class Meta:
        model = CustomEmailTemplate
        fields = [
            'slug',
            'name',
            'description',
            'subject_template',
            'puck_data',
            'is_active',
        ]

    def validate_slug(self, value):
        """Ensure slug is unique within tenant."""
        if CustomEmailTemplate.objects.filter(slug=value).exists():
            raise serializers.ValidationError(
                f"A template with slug '{value}' already exists."
            )
        return value

    def create(self, validated_data):
        """Set created_by to current user."""
        request = self.context.get('request')
        if request and request.user:
            validated_data['created_by'] = request.user
        return super().create(validated_data)


class CustomEmailTemplateUpdateSerializer(serializers.ModelSerializer):
    """Serializer for updating custom email templates."""

    class Meta:
        model = CustomEmailTemplate
        fields = [
            'name',
            'description',
            'subject_template',
            'puck_data',
            'is_active',
        ]

    def validate_slug(self, value):
        """Ensure slug remains unique if changed."""
        instance = self.instance
        if instance and value != instance.slug:
            if CustomEmailTemplate.objects.filter(slug=value).exists():
                raise serializers.ValidationError(
                    f"A template with slug '{value}' already exists."
                )
        return value
