using Application.Services.Database;
using Application.Services.Database.MongoDB;
using Core.Entities;

namespace Application.Endpoints.Chats;

public class ChatHandler
{
    private readonly IChatMongoDbService _chatMongoDbService;
    private readonly IPatientRepository _patientRepository;
    private readonly IDoctorRepository _doctorRepository;

    public ChatHandler(IChatMongoDbService chatMongoDbService, IPatientRepository patientRepository,
        IDoctorRepository doctorRepository)
    {
        _chatMongoDbService = chatMongoDbService;
        _patientRepository = patientRepository;
        _doctorRepository = doctorRepository;
    }

    public async Task<BaseResponse> HandleSendMessage(SendMessageDto sendMessageDto)
    {
        var validation = new SendMessageValidator();
        var validationResult = await validation.ValidateAsync(sendMessageDto);

        if (!validationResult.IsValid)
        {
            var firstError = validationResult.Errors.FirstOrDefault();
            var errorCode = int.TryParse(firstError.ErrorCode, out var code) ? code : -1;
            var errorMessage = firstError.ErrorMessage;

            return new BaseResponse
            {
                StatusCode = errorCode,
                Message = errorMessage,
                Data = null
            };
        }

        if (!await CheckForUsersExistence(sendMessageDto.Sender, sendMessageDto.Receiver))
        {
            return new BaseResponse
            {
                StatusCode = HttpStatusCodes.BadRequest,
                Message = "Users can't be found in the system.",
                Data = null
            };
        }

        var chatId = ChatIdentifier.GenerateChatId(sendMessageDto.Sender, sendMessageDto.Receiver);
        
        var criteria = new List<(string, string)>();
        criteria.Add(("_id", chatId));

        var documents = await _chatMongoDbService.FindAsync<Chat>(criteria);
        if (!documents.Any())
        {
            return new BaseResponse()
            {
                StatusCode = HttpStatusCodes.NotFound,
                Message = "Access to medical history not found.",
                Data = null
            };
        }

        var chat = documents[0].Messages;
        chat.Add(new Message(sendMessageDto.Sender, sendMessageDto.Message));

        var newChat = new Chat();
        newChat.SetId(chatId);
        newChat.SetMessages(chat);

        await _chatMongoDbService.ModifyAsync("_id", chatId, newChat);
        
        return new BaseResponse
        {
            StatusCode = HttpStatusCodes.NoContent,
            Message = null,
            Data = null
        };
    }

    public async Task<BaseResponse> HandleGetConversation(GetConversationDto getConversationDto)
    {
        var validation = new GetConversationValidator();
        var validationResult = await validation.ValidateAsync(getConversationDto);

        if (!validationResult.IsValid)
        {
            var firstError = validationResult.Errors.FirstOrDefault();
            var errorCode = int.TryParse(firstError.ErrorCode, out var code) ? code : -1;
            var errorMessage = firstError.ErrorMessage;

            return new BaseResponse
            {
                StatusCode = errorCode,
                Message = errorMessage,
                Data = null
            };
        }

        if (!await CheckForUsersExistence(getConversationDto.IdUser1, getConversationDto.IdUser2))
        {
            return new BaseResponse
            {
                StatusCode = HttpStatusCodes.BadRequest,
                Message = "Users can't be found in the system.",
                Data = null
            };
        }

        var chatId = ChatIdentifier.GenerateChatId(getConversationDto.IdUser1, getConversationDto.IdUser2);
        
        var criteria = new List<(string, string)>();
        criteria.Add(("_id", chatId));
        
        Chat? chat = null;

        var documents = await _chatMongoDbService.FindAsync<Chat>(criteria);
        if (!documents.Any())
        {
            chat = new Chat();
            chat.SetId(chatId);

            await _chatMongoDbService.AddAsync(chat);
        }
        else
        {
            chat = documents[0];
        }
        
        return new BaseResponse
        {
            StatusCode = HttpStatusCodes.OK,
            Message = "Fetching messages.",
            Data = chat
        };
    }

    private async Task<bool> CheckForUsersExistence(Guid idUser1, Guid idUser2)
    {
        var firstCheck = await _patientRepository.GetByIdAsync(idUser1) != null &&
                         await _doctorRepository.GetByIdAsync(idUser2) != null;
        
        var secondCheck = await _patientRepository.GetByIdAsync(idUser2) != null &&
                          await _doctorRepository.GetByIdAsync(idUser1) != null;

        return firstCheck || secondCheck;
    }
}