context: using Microsoft.AspNetCore.SignalR;
  using Sio.Cms.Messenger.Models;
  using Newtonsoft.Json.Linq;
  using System;
  using System.Collections.Generic;
  using System.Threading.Tasks;
  using Sio.Cms.Messenger;
  using static Sio.Cms.Messenger.SioChatEnums;
  
  namespace Sio.Cms.Messenger.Hubs
  {
      public class SioChatHub : Hub
      {
          const string receiveMethod = "ReceiveMessage";
          const string defaultRoom = "public";
          const string defaultDevice = "website";
  
          public async Task Join(HubRequest<MessengerConnection> request)
          {
              // Set connection Id
              request.Data.ConnectionId = Context.ConnectionId;
              request.Data.DeviceId = request.Data.DeviceId ?? defaultDevice;
              // Mapping connecting user to db  models
              var user = new ViewModels.SioMessengerUsers.ConnectViewModel(request.Data);
              
              user.CreatedDate = DateTime.UtcNow;
              // Save user and current device to db
              var result = await user.Join();
  
              //  save success
              if (result.IsSucceed)
              {
  
                  //  Send success msg to caller 
                  var getAvailableUsers = ViewModels.SioMessengerUsers.DefaultViewModel.Repository.GetModelListBy(u => u.Status == (int)SioChatEnums.OnlineStatus.Connected);
                  SendToCaller(getAvailableUsers.Data, MessageReponseKey.ConnectSuccess);
                  // Announce every one there's new member
                  SendToAll(user, MessageReponseKey.NewMember, false);
              }
              else
              {
                  //  Send failed msg to caller 
                  SendToConnection(result, MessageReponseKey.ConnectFailed, Context.ConnectionId, false);
              }
  
          }
  
          public void SendMessage(JObject request)
          {
              var data = request.ToObject<HubRequest<HubMessage>>();
              data.Data.CreatedDate = DateTime.UtcNow;
              SendToAll(data.Data, MessageReponseKey.NewMessage, true);
          }
  
          public Task SendMessageToCaller(string message)
          {
              return Clients.Caller.SendAsync(receiveMethod, message);
          }
  
          public Task SendMessageToGroups(string message)
          {
              List<string> groups = new List<string>() { "SignalR Users" };
              return Clients.Groups(groups).SendAsync("ReceiveMessage", message);
          }
  
          private void SendToConnection<T>(T message, MessageReponseKey action, string connectionId, bool isMySelf)
          {
              if (!string.IsNullOrEmpty(connectionId))
              {
  
                  HubResponse<T> result = new HubResponse<T>()
                  {
                      IsSucceed = true,
                      Data = message,
                      ResponseKey = GetResponseKey(action)
                  };
  
                  if (isMySelf)
                  {
  
                      Clients.Client(connectionId).SendAsync(receiveMethod, JObject.FromObject(result));
                  }
                  else
                  {
                      Clients.OthersInGroup(connectionId).SendAsync(receiveMethod, JObject.FromObject(result));
                  }
              }
          }
  
          private void SendToCaller<T>(T message, MessageReponseKey action)
          {
              HubResponse<T> result = new HubResponse<T>()
              {
                  IsSucceed = true,
                  Data = message,
                  ResponseKey = GetResponseKey(action)
              };
              Clients.Caller.SendAsync(receiveMethod, JObject.FromObject(result));
          }
  
          private void SendToGroup<T>(T message, MessageReponseKey action, string groupName, bool isMySelf)
          {
              if (!string.IsNullOrEmpty(groupName))
              {
  
                  HubResponse<T> result = new HubResponse<T>()
                  {
                      IsSucceed = true,
                      Data = message,
                      ResponseKey = GetResponseKey(action)
                  };
  
                  if (isMySelf)
                  {
                      Clients.Group(groupName).SendAsync(receiveMethod, JObject.FromObject(result));
                  }
                  else
                  {
                      Clients.OthersInGroup(groupName).SendAsync(receiveMethod, JObject.FromObject(result));
                  }
              }
          }
  
          private void SendToAll<T>(T message, MessageReponseKey action, bool isMySelf)
          {
              HubResponse<T> result = new HubResponse<T>()
              {
                  IsSucceed = true,
                  Data = message,
                  ResponseKey = GetResponseKey(action)
              };
  
              if (isMySelf)
              {
                  Clients.All.SendAsync(receiveMethod, result);
              }
              else
              {
                  Clients.Others.SendAsync(receiveMethod, result);
              }
          }
  
          private string GetResponseKey<T>(T e)
          {
              return Enum.GetName(typeof(T), e);
          }
  
          #region Team - TODO Write these functions
          /*
          [HubMethodName("getTeam")]
          public async System.Threading.Tasks.Task GetTeam(JObject request)
          {
              string errorMsg = string.Empty;
              int status = 0;
              MessengerHubResponse<ChatTeamViewModel> result = null;
              string action = Enum.GetName(typeof(TeamMessageReponseKey), TeamMessageReponseKey.GetTeam);
              //PaginationModel<ChatTeamViewModel> currentMessages = new PaginationModel<ChatTeamViewModel>();
              try
              {
                  if (TTXTeamMemberRepository<FETeamMemberViewModel>.Instance.CheckIsExists(m => m.TeamId == request.TeamId && m.MemberId == request.UserId && m.Status == (int)MemberStatus.Membered))
                  {
                      ChatTeamViewModel team = await TTXTeamRepository<ChatTeamViewModel>.Instance.GetSingleModelAsync(t => t.Id == request.TeamId);
  
                      team.IsNewMessage = TTXTeamMessageRepository<TeamMessage>.Instance.CountUnseenMessage(team.Id, request.UserId) > 0;
  
                      if (team != null)
                      {
                          team.IsAdmin = request.UserId == team.HostId;
                          if (team.IsAdmin)
                          {
  
                              team.TotalRequest = TTXTeamMemberRepository<FETeamMemberViewModel>.Instance.CountRequests(request.TeamId);
                          }
  
                          result = new MessengerHubResponse<ChatTeamViewModel>()
                          {
                              status = 1,
                              responseKey = string.Format("{0}", action),
                              data = team,
                              errors = null
                          };
                      }
                      else
                      {
                          result = new MessengerHubResponse<ChatTeamViewModel>()
                          {
                              status = 0,
                              responseKey = TeamMessageReponseKey.NotMembered.ToString(),
                              data = null,
                              errors = null
                          };
                      }
                  }
                  else
                  {
                      result = new MessengerHubResponse<ChatTeamViewModel>()
                      {
                          status = 0,
                          responseKey = GameResponseKey.NotAuthorized.ToString(),
                          data = null,
                          errors = new List<string>() { "You are not membered of this team" }
                      };
                      Clients.Caller.receiveMessage(result);
                  }
  
              }
              catch (Exception ex)
              {
                  result = new MessengerHubResponse<ChatTeamViewModel>()
                  {
                      status = 0,
                      responseKey = string.Format("{0}", action),
                      data = null,
                      error = ex.StackTrace
                  };
              }
              finally
              {
                  Clients.Caller.receiveMessage(result);
                  UpdatePlayerConnectionIdAsync(request.UserId);
              }
          }
  
  
          [HubMethodName("getTeamMessages")]
          public async System.Threading.Tasks.Task GetTeamMessages(ApiGetTeamMemberViewMdoel request)
          {
              string errorMsg = string.Empty;
              int status = 0;
              MessengerHubResponse<ChatTeamViewModel> result = null;
              string action = Enum.GetName(typeof(TeamMessageReponseKey), TeamMessageReponseKey.GetTeamMessages);
              //PaginationModel<ChatTeamViewModel> currentMessages = new PaginationModel<ChatTeamViewModel>();
              try
              {
                  if (TTXTeamMemberRepository<FETeamMemberViewModel>.Instance.CheckIsExists(m => m.TeamId == request.TeamId && m.MemberId == request.UserId && m.Status == (int)MemberStatus.Membered))
                  {
                      //var messages = await TTXTeamRepository<ChatTeamViewModel>.Instance.GetModelListByAsync(m => m.Id == request.TeamId, m => m.CreatedDate, "desc", 0, 10);
                      ChatTeamViewModel team = await TTXTeamRepository<ChatTeamViewModel>.Instance.GetSingleModelAsync
  
gt:                         (t => t.Id == request.TeamId);