using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.SignalR; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using MimeKit; using MTWorkHR.Application.Filters; using MTWorkHR.Application.Identity; using MTWorkHR.Application.Mapper; using MTWorkHR.Application.Models; using MTWorkHR.Application.Services; using MTWorkHR.Core.Entities; using MTWorkHR.Core.Entities.Base; using MTWorkHR.Core.Global; using MTWorkHR.Core.UnitOfWork; using MTWorkHR.Infrastructure.Entities; using System; using System.ComponentModel.Design; using System.Linq.Dynamic.Core.Tokenizer; using System.Security.Claims; using static Microsoft.EntityFrameworkCore.DbLoggerCategory.Database; namespace MTWorkHR.API.Chat { [AppAuthorize] public class ChatHub : Hub { private readonly IUnitOfWork _unitOfWork; private readonly GlobalInfo _globalInfo; //private readonly UserService _userService; private readonly ApplicationUserManager _userManager; private readonly ILogger _logger; public ChatHub(IUnitOfWork unitOfWork, GlobalInfo globalInfo, ApplicationUserManager userManager /*, UserService userService*/, ILogger logger) { _unitOfWork = unitOfWork; _globalInfo = globalInfo; // _userService = userService; _userManager = userManager; _logger = logger; } public async Task GetUsers() { var myCompanyUsers = await GetAllCompanyEmployees(); await Clients.Caller.SendAsync("UpdateUserList", myCompanyUsers); } public async Task> GetAllCompanyEmployees() { var response = new List(); try { // Get all employees with the "Employee" role var employees = await _userManager.GetUsersInRoleAsync("Employee"); var companyEmployees = await _userManager.GetUsersInRoleAsync("Employee"); var CompanyId = GetAuthenticatedCompanyId(); var userId = Context.User.Identities.FirstOrDefault()?.FindFirst("uid")?.Value; // Get all message sender and receiver IDs excluding current user var allMessages = await GetAllMessages(); var companyUserIds = allMessages .SelectMany(m => new[] { m.SenderId, m.ReceiverId }).Where(id => id != userId).Distinct().ToHashSet(); // Filter employees who belong to the same company or have messaged the current user var res = employees.Where(e => e.Id != userId && (e.CompanyId == CompanyId || companyUserIds.Contains(e.Id))).ToList(); //var mappedEmployees = MapperObject.Mapper.Map>(res); // Get online users and map to a dictionary for faster lookups var allConnections = await _unitOfWork.HubConnection.GetAllAsync(); var onlineUsers = allConnections.Item1.ToDictionary(c => c.UserId, c => c.SignalrId); // Retrieve last message data for each employee foreach (var emp in res) { var onlineSignalrId = onlineUsers.TryGetValue(emp.Id, out var signalrId) ? signalrId : null; var isOnline = onlineSignalrId != null; var profileImg = ""; // Assuming this is coming from another source if needed // Retrieve last message and unseen count for the employee var lastMessage = await GetLastMessage(emp.Id); // Create ChatUserDto and add to response response.Add(new ChatUserDto( emp.Id, $"{emp.FirstName} {emp.LastName}", onlineSignalrId, emp.Email, isOnline, profileImg, lastMessage.Item2, lastMessage.Item1?.Content, lastMessage.Item1?.CreateDate, emp.FirstName, emp.LastName )); } } catch (Exception e) { _logger.LogError(e, e.Message); } return response; } private long GetAuthenticatedCompanyId() { long CompanyIdLong = 0; var identity = Context.User?.Identities.FirstOrDefault(); var CompanyId = identity!=null ? identity.FindFirst("companyId")?.Value : "0"; if(CompanyId != null) { CompanyIdLong = long.Parse(CompanyId); } return CompanyIdLong; } // Get previous messages between two users public async Task GetPreviousMessages(string contactId) { var userId = Context.User.Identities.FirstOrDefault().FindFirst("uid")?.Value; var allmessages = await _unitOfWork.ChatMessage.GetAllWithChildrenAsync(userId, contactId); // Ensure the query is fully materialized before passing it to SignalR var messagesList = await allmessages.Item1.ToListAsync(); await Clients.Caller.SendAsync("PreviousMessages", messagesList); } // Send a message from one user to another public async Task SendMessage(string receiverUserId, string msg) { try { var userId = Context.User.Identities.FirstOrDefault().FindFirst("uid")?.Value; var userName = Context.User.Identities.FirstOrDefault().FindFirst("name")?.Value; var allConnections = await _unitOfWork.HubConnection.GetAllAsync(); var receiverUser = allConnections.Item1.FirstOrDefault(c => c.UserId == receiverUserId); var receiverconnIdDB = receiverUser != null ? receiverUser.SignalrId : "0"; ChatMessage messag = new ChatMessage { Content = msg, ReceiverId = receiverUserId, ReceiverName = receiverUser?.UserName ?? "", SenderId = userId, SenderName = userName, IsSeen = false }; await _unitOfWork.ChatMessage.AddAsync(messag); await _unitOfWork.CompleteAsync(); await Clients.Client(receiverconnIdDB).SendAsync("ReceiveMessage", messag); await Clients.Caller.SendAsync("ReceiveMessage", messag); } catch (Exception e) { _logger.LogError(e, e.Message); } } public async Task> GetAllMessages() { var userId = Context.User.Identities.FirstOrDefault().FindFirst("uid")?.Value; var allmessages = await _unitOfWork.ChatMessage.GetAllUserMessagesAsync(userId); // Ensure the query is fully materialized before passing it to SignalR var messagesList = await allmessages.Item1.ToListAsync(); return messagesList; } public async Task> GetLastMessage(string contactId) { var userId = Context.User.Identities.FirstOrDefault().FindFirst("uid")?.Value; var allmessages = await _unitOfWork.ChatMessage.GetAllWithChildrenAsync(userId, contactId); // Ensure the query is fully materialized before passing it to SignalR var lastOne = allmessages.Item1.OrderByDescending(m=> m.Id).FirstOrDefault(); var unseen = allmessages.Item1.Count(m=> m.IsSeen == false); return new Tuple( lastOne?? new ChatMessage(), unseen); } //---------------------------------------------------------------------- //---------------------------------------------------------------------- //---------------------------------------------------------------------- //Simple Test Method public async Task SendMessageAll(string user, string message) { await Clients.All.SendAsync("ReceiveMessage", user, message); } public async override Task OnDisconnectedAsync(Exception exception) { var email = Context.User?.FindFirst(ClaimTypes.Email)?.Value; var connections = await _unitOfWork.HubConnection.GetAllAsync(Context.ConnectionId); var currUserId = connections.Item1.Select(c => c.UserId).SingleOrDefault(); await _unitOfWork.HubConnection.DeleteRangeAsync(connections.Item1.ToList()); await _unitOfWork.CompleteAsync(); await Clients.Others.SendAsync("userOff", currUserId); await base.OnDisconnectedAsync(exception); } public override async Task OnConnectedAsync() { try { string currSignalrID = Context.ConnectionId; var email = Context.User?.FindFirst(ClaimTypes.Email)?.Value; var userId = Context.User.Identities.FirstOrDefault().FindFirst("uid")?.Value; var userName = Context.User.Identities.FirstOrDefault().FindFirst("name")?.Value; if (userId != null) //if credentials are correct { //--------------delete var connections = await _unitOfWork.HubConnection.GetAllByUserAsync(userId); await _unitOfWork.HubConnection.DeleteRangeAsync(connections.Item1.ToList()); await _unitOfWork.CompleteAsync(); // HubConnection currUser = new HubConnection { UserId = userId, UserName = userName, SignalrId = currSignalrID, TimeStamp = DateTime.Now }; var newConnection = await _unitOfWork.HubConnection.AddAsync(currUser); await _unitOfWork.CompleteAsync(); ChatUserDto newUser = new ChatUserDto(userId, userName, currSignalrID); await Clients.Caller.SendAsync("authMeResponseSuccess", newUser);//4Tutorial await Clients.Others.SendAsync("userOn", newUser);//4Tutorial } else //if credentials are incorrect { await Clients.Caller.SendAsync("authMeResponseFail"); } } catch (Exception e) { _logger.LogError(e, e.Message); } await base.OnConnectedAsync(); } public void logOut(string userId) { var userIdAuth = Context.User.Identities.FirstOrDefault().FindFirst("uid")?.Value; var connections = _unitOfWork.HubConnection.GetAllAsync(Context.ConnectionId).Result; // var currUserId = connections.Item1.Select(c => c.UserId).SingleOrDefault(); _unitOfWork.HubConnection.DeleteRangeAsync(connections.Item1.ToList()); _unitOfWork.CompleteAsync(); Clients.Caller.SendAsync("logoutResponse"); Clients.Others.SendAsync("userOff", userIdAuth); } public async Task getOnlineUsers() { var allConnections = await _unitOfWork.HubConnection.GetAllAsync(); var currUserId = allConnections.Item1.Where(c => c.SignalrId == Context.ConnectionId).Select(c => c.UserId).SingleOrDefault(); List onlineUsers = allConnections.Item1 .Where(c => c.UserId != currUserId) .Select(c => new ChatUserDto(c.UserId, c.UserName, c.SignalrId) ).ToList(); await Clients.Caller.SendAsync("getOnlineUsersResponse", onlineUsers); } public async Task authMe(PersonalInfo person) { try { string currSignalrID = Context.ConnectionId; //Person tempPerson = ctx.Person.Where(p => p.Username == personInfo.userName && p.Password == personInfo.password) // .SingleOrDefault(); var companyId = Context.User.Identities.FirstOrDefault().FindFirst("companyId")?.Value; var userId = Context.User.Identities.FirstOrDefault().FindFirst("uid")?.Value; var userName = Context.User.Identities.FirstOrDefault().FindFirst("name")?.Value; if (userId != null) //if credentials are correct { Console.WriteLine("\n" + userName + " logged in" + "\nSignalrID: " + currSignalrID); HubConnection currUser = new HubConnection { UserId = userId, UserName = userName, SignalrId = currSignalrID, TimeStamp = DateTime.Now }; var newConnection = await _unitOfWork.HubConnection.AddAsync(currUser); await _unitOfWork.CompleteAsync(); ChatUserDto newUser = new ChatUserDto(userId, userName, currSignalrID); await Clients.Caller.SendAsync("authMeResponseSuccess", newUser);//4Tutorial await Clients.Others.SendAsync("userOn", newUser);//4Tutorial } else //if credentials are incorrect { await Clients.Caller.SendAsync("authMeResponseFail"); } } catch (Exception e) { await Clients.Caller.SendAsync("authMeResponseFail"); } } //public async Task reauthMe(string userId) //{ // string currSignalrID = Context.ConnectionId; // //ApplicationUser tempPerson = ctx.Person.Where(p => p.Id == personId) // // .SingleOrDefault(); // if (userId == _globalInfo.UserId) //if credentials are correct // { // Console.WriteLine("\n" + _globalInfo.UserName + " logged in" + "\nSignalrID: " + currSignalrID); // HubConnection currUser = new HubConnection // { // UserId = _globalInfo.UserId, // SignalrId = currSignalrID, // TimeStamp = DateTime.Now // }; // var newConnection = await _unitOfWork.HubConnection.AddAsync(currUser); // await _unitOfWork.CompleteAsync(); // ChatUserDto newUser = new ChatUserDto(_globalInfo.UserId, _globalInfo.UserName, currSignalrID); // await Clients.Caller.SendAsync("reauthMeResponse", newUser);//4Tutorial // await Clients.Others.SendAsync("userOn", newUser);//4Tutorial // } //} //end of reauthMe } public class PersonalInfo { public string userName { get; set; } public string password { get; set; } public string userId { get; set; } } }