using Common.Dtos.Conversation; using Common.Enums; using Hushian.Application.Contracts.Persistence; using Hushian.Application.Models; using Hushian.Domain.Entites; using Hushian.WebApi; using Microsoft.AspNetCore.Routing.Constraints; using Microsoft.AspNetCore.SignalR; using Microsoft.EntityFrameworkCore; using System; using System.Collections.Generic; using System.ComponentModel.Design; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Hushian.Application.Services { public class ChatService { private readonly IGenericRepository _ConversationRepository; private readonly IGenericRepository _ConversationResponseRepository; private readonly CompanyService _companyService; private readonly UserService _userService; private readonly GroupService _groupService; private readonly ExperService _experService; private readonly IHubContext _hubContext; public ChatService(IGenericRepository conversationRepository, IGenericRepository conversationResponseRepository, CompanyService companyService, UserService userService, GroupService groupService, ExperService experService, IHubContext hubContext) { _ConversationRepository = conversationRepository; _ConversationResponseRepository = conversationResponseRepository; _companyService = companyService; _userService = userService; _groupService = groupService; _experService = experService; _hubContext = hubContext; } public async Task> GeChatsByExperID(int ExperID, ConversationStatus status) => await _ConversationRepository.Get() .Include(inc => inc.Group) .Include(inc => inc.ConversationResponses).ThenInclude(tinc => tinc.Exper) .Where(w => w.ConversationResponses.Any(a => a.ExperID == ExperID) && w.Status == status) .Select(s => new ChatItemDto() { ID = s.ID, ExperID = s.ConversationResponses.OrderBy(o => o.ID).Last(l => l.ExperID.HasValue).ExperID, ExperFullName = s.ConversationResponses.OrderBy(o => o.ID).Last(l => l.ExperID.HasValue).Exper.FullName, GroupID = s.GroupID, GroupName = s.Group.Name, LastText = s.ConversationResponses.OrderBy(o => o.ID).Last().Text, LastMsgdate = s.Cdatetime.GetDatePersian(), LastMsgtime = s.Cdatetime.GetTime(), LastMsgType = s.ConversationResponses.OrderBy(o => o.ID).Last().Type, status = s.Status, UserID = s.UserID, UserFullName = string.IsNullOrEmpty(s.User.FullName) ? s.User.Mobile : s.User.FullName, Responses = s.ConversationResponses.Select(ss => new ChatItemResponseDto() { ChatItemID = ss.ConversationID, ExperID = ss.ExperID, ExperName = ss.Exper.FullName, FileContent = ss.FileContent, FileName = ss.FileName, FileType = ss.FileType, ID = ss.ID, IsRead = ss.IsRead, text = ss.Text, Type = ss.Type }).ToList() }).ToListAsync(); public async Task> GetChatsByCompanyID(int CompanyID, ConversationStatus status) => await _ConversationRepository.Get() .Include(inc => inc.Group) .Include(inc => inc.ConversationResponses).ThenInclude(tinc => tinc.Exper) .Where(w => w.CompanyID == CompanyID && w.Status == status) .Select(s => new ChatItemDto() { ID = s.ID, ExperID = s.ConversationResponses.OrderBy(o => o.ID).Last(l => l.ExperID.HasValue).ExperID, ExperFullName = s.ConversationResponses.OrderBy(o => o.ID).Last(l => l.ExperID.HasValue).Exper.FullName, GroupID = s.GroupID, GroupName = s.Group.Name, LastText = s.ConversationResponses.OrderBy(o => o.ID).Last().Text, LastMsgdate = s.Cdatetime.GetDatePersian(), LastMsgtime = s.Cdatetime.GetTime(), LastMsgType = s.ConversationResponses.OrderBy(o => o.ID).Last().Type, status = s.Status, UserID = s.UserID, UserFullName = string.IsNullOrEmpty(s.User.FullName) ? s.User.Mobile : s.User.FullName, Responses = s.ConversationResponses.Select(ss => new ChatItemResponseDto() { ChatItemID = ss.ConversationID, ExperID = ss.ExperID, ExperName = ss.Exper.FullName, FileContent = ss.FileContent, FileName = ss.FileName, FileType = ss.FileType, ID = ss.ID, IsRead = ss.IsRead, text = ss.Text, Type = ss.Type }).ToList() }).ToListAsync(); public async Task> ChatsAwaitingOurResponse(int CompanyID, int? ExperID) { int[]? groupallow = null; if (ExperID.HasValue) { var groups = await _groupService.GetGroupsExper(ExperID.Value); if (groups.Count > 0) groupallow = groups.Select(s => s.ID).ToArray(); } var request = _ConversationRepository.Get() .Include(inc => inc.Group) .Include(inc => inc.ConversationResponses).ThenInclude(tinc => tinc.Exper) .Where(w => w.Status == ConversationStatus.Recorded && w.CompanyID == CompanyID); if (groupallow != null) request = request.Where(w => !w.GroupID.HasValue || groupallow.Contains(w.GroupID.Value)); return await request.Select(s => new ChatItemDto() { ID = s.ID, ExperID = s.ConversationResponses.OrderBy(o => o.ID).Last(l => l.ExperID.HasValue).ExperID, ExperFullName = s.ConversationResponses.OrderBy(o => o.ID).Last(l => l.ExperID.HasValue).Exper.FullName, GroupID = s.GroupID, GroupName = s.Group.Name, LastText = s.ConversationResponses.OrderBy(o => o.ID).Last().Text, LastMsgdate = s.Cdatetime.GetDatePersian(), LastMsgtime = s.Cdatetime.GetTime(), LastMsgType = s.ConversationResponses.OrderBy(o => o.ID).Last().Type, status = s.Status, UserID = s.UserID, UserFullName = string.IsNullOrEmpty(s.User.FullName) ? s.User.Mobile : s.User.FullName, Responses = s.ConversationResponses.Select(ss => new ChatItemResponseDto() { ChatItemID = ss.ConversationID, ExperID = ss.ExperID, ExperName = ss.Exper.FullName, FileContent = ss.FileContent, FileName = ss.FileName, FileType = ss.FileType, ID = ss.ID, IsRead = ss.IsRead, text = ss.Text, Type = ss.Type }).ToList() }).ToListAsync(); } //------------------------ public async Task> NewChat(ADD_ConversationDto dto, ConversationType type = ConversationType.UE) { var Response = new ResponseBase(); if (await _companyService.AnyCompany(dto.CompanyID)) { if (await _userService.AnyUser(dto.UserID)) { if (type == ConversationType.Bot) { if (!await _companyService.AllowBot(dto.CompanyID)) { Response.Errors.Add("دستیار گفتگو هوشمند برای این شرکت در دسترس نمی باشد"); return Response; } } if (!dto.GroupID.HasValue || (dto.GroupID.HasValue && await _groupService.AnyGroup(dto.GroupID.Value) && await _groupService.CHeckGroupMemberCompany(dto.GroupID.Value, dto.CompanyID))) { Conversation conversation = new Conversation() { CompanyID = dto.CompanyID, UserID = dto.UserID, GroupID = dto.GroupID, ConversationResponses = new List() { new() { Text = dto.Question, Type = type } } }; var mi = await _ConversationRepository.ADD(conversation); if (mi.ID > 0) Response.Value = await _ConversationRepository.Get() .Include(inc => inc.Group).Include(inc => inc.ConversationResponses).ThenInclude(tinc => tinc.Exper) .Where(w => w.ID == mi.ID) .Select(s => new ChatItemDto() { ID = s.ID, ExperID = s.ConversationResponses.OrderBy(o => o.ID).Last(l => l.ExperID.HasValue).ExperID, ExperFullName = s.ConversationResponses.OrderBy(o => o.ID).Last(l => l.ExperID.HasValue).Exper.FullName, GroupID = s.GroupID, GroupName = s.Group.Name, LastText = s.ConversationResponses.OrderBy(o => o.ID).Last().Text, LastMsgdate = s.Cdatetime.GetDatePersian(), LastMsgtime = s.Cdatetime.GetTime(), LastMsgType = s.ConversationResponses.OrderBy(o => o.ID).Last().Type, status = s.Status, UserID = s.UserID, UserFullName = string.IsNullOrEmpty(s.User.FullName) ? s.User.Mobile : s.User.FullName, Responses = s.ConversationResponses.Select(ss => new ChatItemResponseDto() { ChatItemID = ss.ConversationID, ExperID = ss.ExperID, ExperName = ss.Exper.FullName, FileContent = ss.FileContent, FileName = ss.FileName, FileType = ss.FileType, ID = ss.ID, IsRead = ss.IsRead, text = ss.Text, Type = ss.Type }).ToList() }).FirstOrDefaultAsync(); Response.Success = mi.ID > 0; if (Response.Success) await NewChatInHub(dto.CompanyID); } else Response.Errors.Add("شناسه گروه صحیح نمی باشد"); } else Response.Errors.Add("شناسه کاربر یافت نشد"); } else Response.Errors.Add("شناسه شرکت یافت نشد"); return Response; } public async Task> ADDChatResponse(ADD_ConversationResponseDto dto, int? ExperID) { var Response = new ResponseBase(); if (dto.Type == ConversationType.EU && !ExperID.HasValue) { Response.Errors.Add("کارشناس گفتگو را مشخص گنید"); } else { var convModel = await _ConversationRepository.Get() .Include(inc => inc.ConversationResponses) .FirstOrDefaultAsync(w => w.ID == dto.ConversationID); if (convModel != null) { if (ExperID.HasValue && !await _experService.CheckExperInCompany(convModel.CompanyID, ExperID.Value)) { Response.Errors.Add("کارشناس گفتگو صحیح نمی باشد"); return Response; } ConversationResponse response = new ConversationResponse() { ConversationID = convModel.ID, Text = dto.Text, Type = dto.Type, ExperID = ExperID, FileContent = dto.FileContent, FileType = dto.FileType, FileName = dto.FileName }; var statuschangedb = await _ConversationResponseRepository.ADD(response); Response.Value = new ChatItemResponseDto() { ChatItemID = statuschangedb.ConversationID, ExperID = statuschangedb.ExperID, ExperName = /*statuschangedb.Exper.FullName*/ "", FileContent = statuschangedb.FileContent, FileName = statuschangedb.FileName, FileType = statuschangedb.FileType, ID = statuschangedb.ID, IsRead = statuschangedb.IsRead, text = statuschangedb.Text, Type = statuschangedb.Type }; Response.Success = statuschangedb.ID > 0; if (convModel.Status == ConversationStatus.Recorded && Response.Success) { convModel.Status = ConversationStatus.InProgress; await _ConversationRepository.UPDATE(convModel); } if (dto.Type != ConversationType.UE) await WriteInHubFromCompany(Response.Value, convModel.UserID); else { var modelA = convModel.ConversationResponses.OrderBy(o => o.ID) .LastOrDefault(l => l.Type == ConversationType.EU || l.Type == ConversationType.CU); if (modelA != null) { int userid = 0; if (modelA.Type == ConversationType.EU) userid = modelA.ExperID.Value; else if (modelA.Type == ConversationType.CU) userid = modelA.conversation.CompanyID; await WriteInHubFromUser(Response.Value, userid); } } } else Response.Errors.Add("گفتگویی یافت نشد"); } return Response; } public async Task FinishChat(int ChatID, int CompanyID, int? ExperID) { var convModel = await _ConversationRepository.Get() .Include(inc => inc.ConversationResponses) .FirstOrDefaultAsync(w => w.ID == ChatID && w.CompanyID == CompanyID); if (ExperID.HasValue && !convModel.ConversationResponses.Any(a => a.ExperID == ExperID.Value)) return false; if (convModel != null && convModel.Status != ConversationStatus.Finished) { convModel.Status = ConversationStatus.Finished; convModel.FinishedDateTime = DateTime.Now; return await _ConversationRepository.UPDATEBool(convModel); } return true; } public async Task OpenChat(int ChatID, int CompanyID, int? ExperID) { var convModel = await _ConversationRepository.Get() .Include(inc => inc.ConversationResponses) .FirstOrDefaultAsync(w => w.ID == ChatID && w.CompanyID == CompanyID); if (ExperID.HasValue && !convModel.ConversationResponses.Any(a => a.ExperID == ExperID.Value)) return false; if (convModel != null && convModel.Status == ConversationStatus.Finished) { convModel.Status = ConversationStatus.InProgress; convModel.FinishedDateTime = null; return await _ConversationRepository.UPDATEBool(convModel); } return true; } public async Task FinishChatFromUser(int ChatID, int userID) { var convModel = await _ConversationRepository.Get() .Include(inc => inc.ConversationResponses) .FirstOrDefaultAsync(w => w.ID == ChatID && w.UserID == userID); if (convModel != null && convModel.Status != ConversationStatus.Finished) { convModel.Status = ConversationStatus.Finished; convModel.FinishedDateTime = DateTime.Now; return await _ConversationRepository.UPDATEBool(convModel); } return true; } public async Task Attachedto(int ChatID, int? FromExperID, int toExperID, int CompanyID) { return false; } public async Task MarkAsReadChatItem(int ID, ConversationType Type, int? ExperID) { var item = await _ConversationResponseRepository.Get() .Include(inc => inc.conversation).FirstOrDefaultAsync(w => w.ID == ID /*&& !w.ExperID.HasValue*/ && w.conversation.Status != ConversationStatus.Finished); if (item != null) { if (Type != item.Type) { if (Type != ConversationType.UE && item.conversation.Status == ConversationStatus.Recorded) { item.conversation.Status = ConversationStatus.InProgress; await _ConversationRepository.UPDATE(item.conversation); } if (!item.IsRead) { item.IsRead = true; item.ReadDateTime = DateTime.Now; if (!item.ExperID.HasValue) item.ExperID = ExperID; if( (await _ConversationResponseRepository.UPDATE(item)) != null) { int userID = 0; if (item.Type == ConversationType.EU) userID = item.ExperID.Value; else if (item.Type == ConversationType.CU) userID = item.conversation.CompanyID; else if (item.Type == ConversationType.UE) userID = item.conversation.UserID; await CheckMarkAsReadInHub(item.ID, userID); return true; } } } } return false; } public async Task> GetLastOpenChatInCompany(int CompanyID, int UserID) { ResponseBase Response = new(); Response.Value = await _ConversationRepository.Get() .Include(inc => inc.Group) .Include(inc => inc.ConversationResponses).ThenInclude(tinc => tinc.Exper) .Where(w => w.UserID == UserID && w.CompanyID == CompanyID && w.Status != ConversationStatus.Finished) .OrderByDescending(o => o.ID) .Select(s => new ChatItemDto() { ID = s.ID, ExperID = s.ConversationResponses.OrderBy(o => o.ID).Last(l => l.ExperID.HasValue).ExperID, ExperFullName = s.ConversationResponses.OrderBy(o => o.ID).Last(l => l.ExperID.HasValue).Exper.FullName, GroupID = s.GroupID, GroupName = s.Group.Name, LastText = s.ConversationResponses.OrderBy(o => o.ID).Last().Text, LastMsgdate = s.Cdatetime.GetDatePersian(), LastMsgtime = s.Cdatetime.GetTime(), LastMsgType = s.ConversationResponses.OrderBy(o => o.ID).Last().Type, status = s.Status, UserID = s.UserID, UserFullName = string.IsNullOrEmpty(s.User.FullName) ? s.User.Mobile : s.User.FullName, Responses = s.ConversationResponses.Select(ss => new ChatItemResponseDto() { ChatItemID = ss.ConversationID, ExperID = ss.ExperID, ExperName = ss.Exper.FullName, FileContent = ss.FileContent, FileName = ss.FileName, FileType = ss.FileType, ID = ss.ID, IsRead = ss.IsRead, text = ss.Text, Type = ss.Type }).ToList() }).FirstOrDefaultAsync(); if (Response.Value != null) Response.Success = true; return Response; } public async Task> GetChat(int ChatID, int UserID) { ResponseBase Response = new(); Response.Value = await _ConversationRepository.Get() .Include(inc => inc.Group) .Include(inc => inc.ConversationResponses).ThenInclude(tinc => tinc.Exper) .Where(w => w.UserID == UserID && w.ID == ChatID) .OrderByDescending(o => o.ID) .Select(s => new ChatItemDto() { ID = s.ID, ExperID = s.ConversationResponses.OrderBy(o => o.ID).Last(l => l.ExperID.HasValue).ExperID, ExperFullName = s.ConversationResponses.OrderBy(o => o.ID).Last(l => l.ExperID.HasValue).Exper.FullName, GroupID = s.GroupID, GroupName = s.Group.Name, LastText = s.ConversationResponses.OrderBy(o => o.ID).Last().Text, LastMsgdate = s.Cdatetime.GetDatePersian(), LastMsgtime = s.Cdatetime.GetTime(), LastMsgType = s.ConversationResponses.OrderBy(o => o.ID).Last().Type, status = s.Status, UserID = s.UserID, UserFullName = string.IsNullOrEmpty(s.User.FullName) ? s.User.Mobile : s.User.FullName, Responses = s.ConversationResponses.Select(ss => new ChatItemResponseDto() { ChatItemID = ss.ConversationID, ExperID = ss.ExperID, ExperName = ss.Exper.FullName, FileContent = ss.FileContent, FileName = ss.FileName, FileType = ss.FileType, ID = ss.ID, IsRead = ss.IsRead, text = ss.Text, Type = ss.Type }).ToList() }).FirstOrDefaultAsync(); if (Response.Value != null) Response.Success = true; return Response; } public async Task WriteInHubFromCompany(ChatItemResponseDto item, int UserID) { await _hubContext.Clients.User(UserID.ToString()) .SendAsync("ReceiveNewChatItemFromCompany", item); //// فرض: لیستی از کاربرانی که به گفتگو دسترسی دارند //var usernames = new List(); //foreach (var usn in usernames) //{ // //await _hubContext.Clients.User(usn) // // .SendAsync("ReceiveNewConversation", conv.Id, conv.Title); //} } public async Task WriteInHubFromUser(ChatItemResponseDto item, int UserID) { await _hubContext.Clients.User(UserID.ToString()) .SendAsync("ReceiveNewChatItemFromUser", item); } public async Task CheckMarkAsReadInHub(int item, int UserID) { await _hubContext.Clients.User(UserID.ToString()) .SendAsync("CheckMarkAsRead", item); } public async Task NewChatInHub(int CompanyID) { await _hubContext.Clients.All .SendAsync("NewChat", CompanyID); } } }