private static async Task <BotConversation> GetConversationByUserId(string userId)
        {
            // TODO: extract this and inject an instance of IBotConversationProvider
            await DocumentClient.GetDocumentCollectionAsync();

            BotConversation conversation = await DocumentClient.GetItemAsync <BotConversation>(c => c.UserId == userId);

            return(conversation);
        }
        private static async Task PostToConversation(IncomingSms incomingSms, BotConversation conversation, ILogger log)
        {
            log.LogInformation($"Posting message to conversationId {conversation.ConversationId}");

            dynamic from = new ExpandoObject();

            from.id   = incomingSms.SourceNumber;
            from.name = incomingSms.SourceNumber;
            from.role = null;

            dynamic channelData = new ExpandoObject();

            channelData.UniqueLearnerNumber     = conversation.UniqueLearnerNumber;
            channelData.StandardCode            = conversation.StandardCode;
            channelData.ApprenticeshipStartDate = conversation.ApprenticeshipStartDate;
            channelData.NotifyMessage           = new NotifyMessage
            {
                Id                = incomingSms.Id,
                DateReceived      = incomingSms.DateReceived.ToString(CultureInfo.InvariantCulture),
                DestinationNumber = incomingSms.DestinationNumber,
                SourceNumber      = incomingSms.SourceNumber,
                Message           = incomingSms.Message,
                Type              = "callback",
            };

            var messageContent = new BotConversationMessage
            {
                Type        = "message",
                From        = from,
                Text        = incomingSms.Message,
                ChannelData = channelData
            };

            var         json    = JsonConvert.SerializeObject(messageContent);
            HttpContent content = new StringContent(json);

            content.Headers.ContentType = new MediaTypeHeaderValue("application/json");

            HttpResponseMessage postMessageTask = await DirectLineClient.PostAsync($"/v3/directline/conversations/{conversation.ConversationId}/activities", content);

            if (postMessageTask.IsSuccessStatusCode)
            {
                string response = await postMessageTask.Content.ReadAsStringAsync();

                dynamic jsonResponse = JsonConvert.DeserializeObject(response);
                log.LogInformation($"Received response from Bot Client: {jsonResponse.id}");
            }
            else
            {
                var message = $"Could not post conversation to DirectLineClient. {postMessageTask.StatusCode}: {postMessageTask.ReasonPhrase}";
                throw new BotConnectorException(message);
            }
        }
        private static async Task StartNewConversation(IncomingSms incomingSms, ILogger log)
        {
            log.LogInformation($"Starting new conversation with {incomingSms.SourceNumber}");

            var content = new StringContent(string.Empty);

            var startConversationTask = await DirectLineClient.PostAsync("/v3/directline/conversations", content);

            var conversation = new BotConversation();

            if (startConversationTask.IsSuccessStatusCode)
            {
                string response = await startConversationTask.Content.ReadAsStringAsync();

                dynamic jsonResponse = JsonConvert.DeserializeObject(response);
                log.LogInformation($"Started new conversation with id {jsonResponse.conversationId}");

                // TODO: write the conversation ID to a session log with the mobile phone number
                conversation.UserId                  = incomingSms.SourceNumber; // TODO: [security] hash this please!
                conversation.ConversationId          = jsonResponse.conversationId;
                conversation.UniqueLearnerNumber     = incomingSms.UniqueLearnerNumber;
                conversation.StandardCode            = incomingSms.StandardCode;
                conversation.ApprenticeshipStartDate = incomingSms.ApprenticeshipStartDate;

                BotConversation newSession = await DocumentClient.UpsertItemAsync(conversation);

                if (newSession == null)
                {
                    var message = $"Could not create session object for conversation id {conversation.ConversationId}";
                    throw new BotConnectorException(message);
                }

                if (incomingSms.Message != null)
                {
                    await PostToConversation(incomingSms, conversation, log);
                }
            }
            else
            {
                var message = $"Could not start new conversation with DirectLineClient. {startConversationTask.StatusCode}: {startConversationTask.ReasonPhrase}";
                throw new BotConnectorException(message);
            }
        }
        public static async Task Run(
            [ServiceBusTrigger("%IncomingMessageQueueName%", Connection = "ServiceBusConnection")]
            string queueMessage,
            [Inject] SettingsProvider configuration,
            ILogger log,
            ExecutionContext context)
        {
            Configuration  = configuration;
            currentContext = context;
            IncomingSms incomingSms = JsonConvert.DeserializeObject <IncomingSms>(queueMessage);

            try
            {
                log.LogInformation($"Response received from {incomingSms.SourceNumber}, sending to bot...");

                string userId = incomingSms.SourceNumber; // TODO: [security] hash me please!
                // If we key this on unique survey to user then we can have different conversationId's per survey run for the same number
                BotConversation conversation = await GetConversationByUserId(userId);

                if (conversation == null)
                {
                    await StartNewConversation(incomingSms, log);
                }
                else
                {
                    await PostToConversation(incomingSms, conversation, log);
                }
            }
            catch (MessageLockLostException e)
            {
                log.LogError($"DeliverMessageToBot MessageLockLostException [{context.FunctionName}|{context.InvocationId}]", e, e.Message);
            }
            catch (Exception e)
            {
                log.LogError($"DeliverMessageToBot ERROR: {e.Message}", e, e.Message);
                DirectLineClient.CancelPendingRequests();
                throw new BotConnectorException("Something went wrong when relaying the message to the bot framework", e);
            }
        }