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.SignalR;
using Microsoft.EntityFrameworkCore;

namespace Hushian.Application.Services
{
    public class ConversationService
    {
        private readonly IGenericRepository<Conversation> _ConversationRepository;
        private readonly IGenericRepository<ConversationResponse> _ConversationResponseRepository;
        private readonly CompanyService _companyService;
        private readonly UserService _userService;
        private readonly GroupService _groupService;
        private readonly ExperService _experService;
        private readonly IHubContext<ChatNotificationHub> _hubContext;

        public ConversationService(
            IGenericRepository<Conversation> conversationRepository
            , IGenericRepository<ConversationResponse> conversationResponseRepository
            , CompanyService companyService, UserService userService, GroupService groupService
            , ExperService experService, IHubContext<ChatNotificationHub> hubContext)
        {
            _ConversationRepository = conversationRepository;
            _ConversationResponseRepository = conversationResponseRepository;
            _companyService = companyService;
            _userService = userService;
            _groupService = groupService;
            _experService = experService;
            _hubContext = hubContext;
        }

        public async Task<ResponseBase<Read_ConversationDto>> NewConversation(ADD_ConversationDto dto, ConversationType type = ConversationType.UE)
        {
            var Response = new ResponseBase<Read_ConversationDto>();
            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<ConversationResponse>() { new() { Text = dto.Question, Type = type } }
                        };
                        var mi = await _ConversationRepository.ADD(conversation);
                        Response.Value = new Read_ConversationDto()
                        {
                            ID = mi.ID,
                            ExperID = mi.ConversationResponses.OrderBy(o => o.ID).Last().ExperID,
                            ExperFullName = /*mi.ConversationResponses.OrderBy(o => o.ID).Last().Exper.FullName*/ "",
                            GroupID = mi.GroupID,
                            GroupName = /*mi.Group.Name*/ "",
                            LastText = mi.ConversationResponses.OrderBy(o => o.ID).Last().Text,
                            LastMsgdate = mi.Cdatetime.GetDatePersian(),
                            LastMsgtime = mi.Cdatetime.GetTime(),
                            LastMsgType = mi.ConversationResponses.OrderBy(o => o.ID).Last().Type,
                            NoReadCount = mi.ConversationResponses.Count(c => !c.IsRead),
                            status = mi.Status,
                            UserID = mi.UserID,
                            UserFullName = /*string.IsNullOrEmpty(mi.User.FullName) ? mi.User.Mobile : mi.User.FullName*/ ""

                        };
                        Response.Success = mi.ID > 0;
                    }
                    else Response.Errors.Add("شناسه گروه صحیح نمی باشد");



                }
                else Response.Errors.Add("شناسه کاربر یافت نشد");

            }
            else Response.Errors.Add("شناسه شرکت یافت نشد");


            return Response;
        }
        public async Task<ResponseBase<Read_ConversationResponseDto>> NewConversationResponse(ADD_ConversationResponseDto dto, int? ExperID)
        {
            var Response = new ResponseBase<Read_ConversationResponseDto>();
            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 Read_ConversationResponseDto()
                    {
                        ConversationID = 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);
                    }
                }
                else Response.Errors.Add("گفتگویی یافت نشد");
            }

            return Response;
        }
        public async Task<List<Read_ConversationDto>> GEtConversation(int UserID,int CompanyID)
        => await _ConversationRepository.Get()
                .Include(inc => inc.Group)
                .Include(inc => inc.ConversationResponses).ThenInclude(tinc => tinc.Exper)
            .Where(w => w.UserID == UserID && w.CompanyID==CompanyID)
                .Select(s => new Read_ConversationDto()
                {
                    ID=s.ID,
                    ExperID = s.ConversationResponses.OrderBy(o => o.ID).Last().ExperID,
                    ExperFullName = s.ConversationResponses.OrderBy(o => o.ID).Last().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,
                    NoReadCount = s.ConversationResponses.Count(c => !c.IsRead),
                    status = s.Status,
                    UserID = s.UserID,
                    UserFullName = string.IsNullOrEmpty(s.User.FullName) ? s.User.Mobile : s.User.FullName

                }).ToListAsync();
        public async Task<List<Read_ConversationResponseDto>> GetConversationItems(int ConversationID)
        {
              return await  _ConversationResponseRepository.Get()
                    .Include(inc=>inc.Exper)
                    .Where(w => w.ConversationID == ConversationID)
                    .Select(s => new Read_ConversationResponseDto()
                    {
                        ConversationID=s.ConversationID,
                        ExperID=s.ExperID,
                        ExperName=s.Exper.FullName,
                        FileContent=s.FileContent,
                        FileName=s.FileName,
                        FileType=s.FileType,
                        ID= s.ID,
                        IsRead=s.IsRead,
                        text=s.Text,
                        Type = s.Type
                    }).ToListAsync();
                
           
        }
        public async Task<List<Read_ConversationDto>> GetConversationByExperID(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 Read_ConversationDto()
                {
                    ID=s.ID,
                    ExperID = s.ConversationResponses.OrderBy(o => o.ID).Last().ExperID,
                    ExperFullName = s.ConversationResponses.OrderBy(o => o.ID).Last().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,
                    NoReadCount = s.ConversationResponses.Count(c => !c.IsRead),
                    status = s.Status,
                    UserID = s.UserID,
                    UserFullName = string.IsNullOrEmpty(s.User.FullName) ? s.User.Mobile : s.User.FullName

                }).ToListAsync();
        public async Task<List<Read_ConversationDto>> GetConversationByCompanyID(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 Read_ConversationDto()
                {
                    ID = s.ID,
                    ExperID = s.ConversationResponses.OrderBy(o => o.ID).Last().ExperID,
                    ExperFullName = s.ConversationResponses.OrderBy(o => o.ID).Last().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,
                    NoReadCount = s.ConversationResponses.Count(c => !c.IsRead),
                    status = s.Status,
                    UserID = s.UserID,
                    UserFullName = string.IsNullOrEmpty(s.User.FullName) ? s.User.Mobile : s.User.FullName

                }).ToListAsync();
        public async Task<List<Read_ConversationDto>> ConversationAwaitingOurResponse(int CompanyID)
     => await _ConversationRepository.Get()
                .Include(inc => inc.Group)
                .Include(inc => inc.ConversationResponses).ThenInclude(tinc => tinc.Exper)
            .Where(w => w.Status== ConversationStatus.Recorded && w.CompanyID == CompanyID)
                .Select(s => new Read_ConversationDto()
                {
                    ID = s.ID,
                    ExperID = s.ConversationResponses.OrderBy(o=>o.ID).Last().ExperID,
                    ExperFullName = s.ConversationResponses.OrderBy(o => o.ID).Last().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,
                    NoReadCount = s.ConversationResponses.Count(c => !c.IsRead),
                    status = s.Status,
                    UserID = s.UserID,
                    UserFullName = string.IsNullOrEmpty(s.User.FullName) ? s.User.Mobile : s.User.FullName

                }).ToListAsync();
        public async Task<bool> FinishConversation(int ConversationID)
        {
            var convModel = await _ConversationRepository.Get()
                             .Include(inc => inc.ConversationResponses)
                             .FirstOrDefaultAsync(w => w.ID == ConversationID);

            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<bool> MarkAsReadConversationItem(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;
                        item.ExperID = ExperID;
                        return (await _ConversationResponseRepository.UPDATE(item)) != null;
                    }
                }
               

            }
            return false;
        }
        public async Task<int> GetCountQueueCompany(int CompanyID, int GroupID = 0)
        {
            var request = _ConversationRepository.Get()
                  .Where(w => w.CompanyID == CompanyID && w.Status!=ConversationStatus.Finished);
            if (GroupID != 0)
                request = request.Where(w => w.GroupID == GroupID);
            return await request.CountAsync();
        }
        public async Task WriteInHub(ConversationResponse item)
        {
            // فرض: لیستی از کاربرانی که به گفتگو دسترسی دارند
            var usernames = new List<string>();

            foreach (var usn in usernames)
            {
                //await _hubContext.Clients.User(usn)
                //    .SendAsync("ReceiveNewConversation", conv.Id, conv.Title);
            }
        }
    }
}
