/// <summary>
        ///   Builds a batch <see cref="AmqpMessage" /> from a set of <see cref="AmqpMessage" />.
        /// </summary>
        ///
        /// <param name="source">The set of messages to use as the body of the batch message.</param>
        /// <param name="firstMessage"></param>
        ///
        /// <returns>The batch <see cref="AmqpMessage" /> containing the source messages.</returns>
        ///
        private static AmqpMessage BuildAmqpBatchFromMessages(
            IEnumerable <AmqpMessage> source,
            SBMessage firstMessage = null)
        {
            AmqpMessage batchEnvelope;

            var batchMessages = source.ToList();

            if (batchMessages.Count == 1)
            {
                batchEnvelope = batchMessages[0];
            }
            else
            {
                batchEnvelope = AmqpMessage.Create(batchMessages.Select(message =>
                {
                    message.Batchable       = true;
                    using var messageStream = message.ToStream();
                    return(new Data {
                        Value = ReadStreamToArraySegment(messageStream)
                    });
                }));

                batchEnvelope.MessageFormat = AmqpConstants.AmqpBatchedMessageFormat;
            }

            if (firstMessage?.MessageId != null)
            {
                batchEnvelope.Properties.MessageId = firstMessage.MessageId;
            }
            if (firstMessage?.SessionId != null)
            {
                batchEnvelope.Properties.GroupId = firstMessage.SessionId;
            }

            if (firstMessage?.PartitionKey != null)
            {
                batchEnvelope.MessageAnnotations.Map[AmqpMessageConverter.PartitionKeyName] =
                    firstMessage.PartitionKey;
            }

            if (firstMessage?.ViaPartitionKey != null)
            {
                batchEnvelope.MessageAnnotations.Map[AmqpMessageConverter.ViaPartitionKeyName] =
                    firstMessage.ViaPartitionKey;
            }

            batchEnvelope.Batchable = true;
            return(batchEnvelope);
        }
        /// <summary>
        ///   Builds a batch <see cref="AmqpMessage" /> from a set of <see cref="SBMessage" />
        ///   optionally propagating the custom properties.
        /// </summary>
        ///
        /// <param name="source">The set of messages to use as the body of the batch message.</param>
        ///
        /// <returns>The batch <see cref="AmqpMessage" /> containing the source messages.</returns>
        ///
        private static AmqpMessage BuildAmqpBatchFromMessage(IEnumerable <SBMessage> source)
        {
            AmqpMessage firstAmqpMessage = null;
            SBMessage   firstMessage     = null;

            return(BuildAmqpBatchFromMessages(
                       source.Select(sbMessage =>
            {
                if (firstAmqpMessage == null)
                {
                    firstAmqpMessage = SBMessageToAmqpMessage(sbMessage);
                    firstMessage = sbMessage;
                    return firstAmqpMessage;
                }
                else
                {
                    return SBMessageToAmqpMessage(sbMessage);
                }
            }).ToList(), firstMessage));
        }
        public static AmqpMessage SBMessageToAmqpMessage(SBMessage sbMessage)
        {
            var amqpMessage = sbMessage.ToAmqpMessage();

            amqpMessage.Properties.MessageId      = sbMessage.MessageId;
            amqpMessage.Properties.CorrelationId  = sbMessage.CorrelationId;
            amqpMessage.Properties.ContentType    = sbMessage.ContentType;
            amqpMessage.Properties.Subject        = sbMessage.Subject;
            amqpMessage.Properties.To             = sbMessage.To;
            amqpMessage.Properties.ReplyTo        = sbMessage.ReplyTo;
            amqpMessage.Properties.GroupId        = sbMessage.SessionId;
            amqpMessage.Properties.ReplyToGroupId = sbMessage.ReplyToSessionId;

            if (sbMessage.TimeToLive != TimeSpan.MaxValue)
            {
                amqpMessage.Header.Ttl = (uint)sbMessage.TimeToLive.TotalMilliseconds;
                amqpMessage.Properties.CreationTime = DateTime.UtcNow;

                if (AmqpConstants.MaxAbsoluteExpiryTime - amqpMessage.Properties.CreationTime.Value > sbMessage.TimeToLive)
                {
                    amqpMessage.Properties.AbsoluteExpiryTime = amqpMessage.Properties.CreationTime.Value + sbMessage.TimeToLive;
                }
                else
                {
                    amqpMessage.Properties.AbsoluteExpiryTime = AmqpConstants.MaxAbsoluteExpiryTime;
                }
            }

            if ((sbMessage.ScheduledEnqueueTime != null) && sbMessage.ScheduledEnqueueTime > DateTimeOffset.MinValue)
            {
                amqpMessage.MessageAnnotations.Map.Add(AmqpMessageConstants.ScheduledEnqueueTimeUtcName, sbMessage.ScheduledEnqueueTime.UtcDateTime);
            }

            if (sbMessage.PartitionKey != null)
            {
                amqpMessage.MessageAnnotations.Map.Add(AmqpMessageConstants.PartitionKeyName, sbMessage.PartitionKey);
            }

            if (sbMessage.TransactionPartitionKey != null)
            {
                amqpMessage.MessageAnnotations.Map.Add(AmqpMessageConstants.ViaPartitionKeyName, sbMessage.TransactionPartitionKey);
            }

            if (sbMessage.ApplicationProperties != null && sbMessage.ApplicationProperties.Count > 0)
            {
                if (amqpMessage.ApplicationProperties == null)
                {
                    amqpMessage.ApplicationProperties = new ApplicationProperties();
                }

                foreach (var pair in sbMessage.ApplicationProperties)
                {
                    if (TryGetAmqpObjectFromNetObject(pair.Value, MappingType.ApplicationProperty, out var amqpObject))
                    {
                        amqpMessage.ApplicationProperties.Map.Add(pair.Key, amqpObject);
                    }
                    else
                    {
                        throw new NotSupportedException(Resources.InvalidAmqpMessageProperty.FormatForUser(pair.Key.GetType()));
                    }
                }
            }

            return(amqpMessage);
        }