protected override async Task HandleTurnAsync(ITurnContext turnContext, ChatUserContext userContext,
                                                      MessageRouter messageRouter, NextDelegate next, CancellationToken cancellationToken = default(CancellationToken))
        {
            Activity activity = turnContext.Activity;

            if (turnContext.TurnState.TryGetValue(typeof(CommandSendMessageProperties).FullName, out object result))
            {
                CommandSendMessageProperties properties = (CommandSendMessageProperties)result;

                //Log broadcast
                if (properties.From.Role == ChatUserRole.Admin && properties.UserId == "*")
                {
                    var allConsumerConservations = await _routingDataManager.GetConsumerConversations();

                    foreach (var consumerConversation in allConsumerConservations)
                    {
                        await _reportDataManager.CreateOrUpdateChatReport(new ChatReportLogCreationModel()
                        {
                            User = properties.From.Role == ChatUserRole.Admin ? new ChatUserModel()
                            {
                                Id = consumerConversation.User.Id
                            } : properties.From,
                            Message = new ChatReportLogModel()
                            {
                                From        = properties.From,
                                Date        = activity.Timestamp.Value.DateTime,
                                Message     = activity.Text,
                                ReportType  = properties.ReportType,
                                Id          = activity.Id,
                                IsBroadcast = true
                            }
                        });
                    }
                }
                else
                {
                    //Log one message
                    ChatReportModel chatReportModel = await _reportDataManager.CreateOrUpdateChatReport(new ChatReportLogCreationModel()
                    {
                        User = properties.From.Role == ChatUserRole.Admin ? new ChatUserModel()
                        {
                            Id = properties.UserId
                        } : properties.From,
                        ChannelId = activity.ChannelId,
                        Message   = new ChatReportLogModel()
                        {
                            From       = properties.From,
                            Date       = activity.Timestamp.Value.DateTime,
                            Message    = activity.Text,
                            ReportType = properties.ReportType,
                            Id         = activity.Id
                        }
                    });

                    turnContext.TurnState.Add(typeof(ChatReportModel).FullName, chatReportModel);
                }

                await next(cancellationToken).ConfigureAwait(false);
            }
        }
        private async Task <Guid?> GetLastReportTypeFromUser(string userId)
        {
            Guid?reportType = null;

            ChatReportModel activeReport = await _reportDataManager.GetActiveChatReportFromUser(userId);

            if (activeReport != null)
            {
                for (int i = activeReport.ReportLogs.Count - 1; 0 <= i; i--)
                {
                    Guid?reportLog = activeReport.ReportLogs[i].ReportType;
                    if (reportLog != null && reportLog != Guid.Empty)
                    {
                        reportType = reportLog;
                        break;
                    }
                }
            }
            return(reportType);
        }
        protected override async Task HandleTurnAsync(ITurnContext turnContext, ChatUserContext userContext,
                                                      MessageRouter messageRouter, NextDelegate next, CancellationToken cancellationToken = default(CancellationToken))
        {
            Activity activity = turnContext.Activity;

            if (activity.TryGetChannelData(out Command command) && command.BaseCommand != Commands.Undefined)
            {
                // Check the activity for commands
                ConversationReference selfConversation = activity.GetConversationReference();
                switch (command.BaseCommand)
                {
                case Commands.GetTranscript:
                    if (userContext.Role == ChatUserRole.Admin)
                    {
                        var conversations = await _reportDataManager.GetActiveChatReports();

                        var readUsersStatus = await _routingDataManager.GetUsersReadStatusPerUser(userContext.Id);

                        await messageRouter.SendTranscriptAsync(activity.Conversation.Id, conversations, readUsersStatus);
                    }
                    else
                    {
                        var conversation = await _reportDataManager.GetActiveChatReportFromUser(activity.From.Id);

                        await messageRouter.SendTranscriptAsync(activity.Conversation.Id, new List <ChatReportModel>() { conversation });
                    }
                    break;

                case Commands.ReadUserMessages:
                    //Update a date that shows the last time a message was read by an admin
                    if (userContext.Role == ChatUserRole.Admin)
                    {
                        if (JsonConvert.DeserializeObject <CommandReadUserMessages>(command.Data.ToString()) is CommandReadUserMessages properties)
                        {
                            var result = await _routingDataManager.UpdateUserReadMessageStatus(activity.From.Id, new ChatUserReadStatusModel()
                            {
                                Date   = properties.Date,
                                UserId = properties.UserId
                            });

                            if (!result)
                            {
                                throw new Exception("Error while executing command ReadUserMessages");
                            }
                        }
                    }
                    break;

                case Commands.EndConversation:
                    //End a conversation by adding an EndDate and delete the user conversation session so broadcast messages aren't sent to them anymore.
                    if (userContext.Role == ChatUserRole.Admin)
                    {
                        if (JsonConvert.DeserializeObject <CommandEndConversation>(command.Data.ToString()) is CommandEndConversation properties)
                        {
                            ChatReportModel userReport = await _reportDataManager.GetActiveChatReportFromUser(properties.UserId);

                            var result = await _reportDataManager.CloseReport(new ChatReportLogCloseModel()
                            {
                                EndDate = DateTime.UtcNow, UserId = properties.UserId
                            });

                            if (result)
                            {
                                var userConversationReference = await _routingDataManager.GetConversationsFromUser(properties.UserId);

                                if (userConversationReference != null && userConversationReference.Count() > 0)
                                {
                                    //Warn the user that the conversation is over
                                    await messageRouter.SendMessageAsync(userConversationReference.ToArray()[0],
                                                                         CommandFactoryHelper.CreateCommandSendMessage(selfConversation.Bot.Id, properties.UserId, selfConversation.User)
                                                                         , "The conversation was ended. If you have an issue, please start a new conversation.");

                                    //Call EndOfConversation on the user
                                    await messageRouter.SendEndConversationAsync(messageRouter.CreateEndOfConversationActivity(userConversationReference.ToArray()[0]));

                                    result = await _routingDataManager.DeleteUserConversation(properties.UserId);

                                    //Tell all admins about end of the conversation
                                    var admins = await _routingDataManager.GetAdminConversations();

                                    admins = _routingDataManager.RemoveSelfConversation(admins, selfConversation);
                                    if (admins != null)
                                    {
                                        foreach (var admin in admins)
                                        {
                                            await messageRouter.SendMessageAsync(admin,
                                                                                 CommandFactoryHelper.CreateCommandEndConversation(selfConversation.Bot.Id, properties.UserId));
                                        }
                                    }

                                    //Send event to event processor... if possible
                                    if (userReport != null)
                                    {
                                        //Sanitize user
                                        string      userId = GetDatabaseUserId(userReport.ChannelId, userReport.User.Id);
                                        DeviceModel device = await _deviceRestService.GetMobileDeviceFromUserId(userId);

                                        //Send close message
                                        await PushClosureMessageToEventProcessorSaga(device.DeviceId);
                                    }
                                }
                            }
                            if (!result)
                            {
                                throw new Exception("Error while executing command EndConversation");
                            }
                        }
                    }
                    break;

                case Commands.SendMessage:
                    if (userContext.Role == ChatUserRole.Admin && !string.IsNullOrWhiteSpace(activity.Text))
                    {
                        if (JsonConvert.DeserializeObject <CommandSendMessageProperties>(command.Data.ToString()) is CommandSendMessageProperties properties)
                        {
                            properties.UserId = properties.UserId;
                            properties.From   = userContext;   //Forcing admin, in case it isn't given by user
                            turnContext.TurnState.Add(typeof(CommandSendMessageProperties).FullName, properties);
                            //We forward to the next middleware
                            await next(cancellationToken).ConfigureAwait(false);
                        }
                        else
                        {
                            throw new Exception("Error while executing command SendMessage");
                        }
                    }
                    break;

                default:
                    if (userContext.Role == ChatUserRole.Admin)
                    {
                        throw new Exception($"Command not recognized: '{command.BaseCommand}'.");
                    }
                    break;
                }
            }
        private async Task <bool> PushMessageToEventProcessorSaga(string message, string channelId, CommandSendMessageProperties consumerMessageProperties, ChatReportModel chatReport)
        {
            try
            {
                if (_serviceBus != null || _serviceBus.BusAccess != null)
                {
                    _logger.LogDebug($"EdisonBot: Pushing message from user '{consumerMessageProperties.From.Id}'.");

                    //Get deviceId
                    string      userId = GetDatabaseUserId(channelId, consumerMessageProperties.UserId);
                    DeviceModel device = await _deviceRestService.GetMobileDeviceFromUserId(userId);

                    //Get last reportType
                    Guid?reportType = consumerMessageProperties.ReportType;
                    if (consumerMessageProperties.ReportType == null || consumerMessageProperties.ReportType == Guid.Empty)
                    {
                        reportType = await GetLastReportTypeFromUser(consumerMessageProperties.UserId);
                    }

                    if (device != null)
                    {
                        IEventSagaReceived newMessage = new EventSagaReceivedEvent()
                        {
                            DeviceId  = device.DeviceId,
                            EventType = "message",
                            Date      = DateTime.UtcNow,
                            Data      = JsonConvert.SerializeObject(new MessageEventMetadata()
                            {
                                UserId       = consumerMessageProperties.UserId,
                                Username     = consumerMessageProperties.From.Name,
                                ReportType   = reportType,
                                Message      = message,
                                ChatReportId = chatReport.ReportId
                            })
                        };
                        await _serviceBus.BusAccess.Publish(newMessage);

                        return(true);
                    }
                }
                return(false);
            }
            catch (Exception e)
            {
                _logger.LogError($"EdisonBot: {e.Message}");
                return(false);
            }
        }