using Application.Services.Database;
using Application.Services.Database.MongoDB;

namespace Application.Endpoints.MedicalHistories.ManageAuthorization;

public class MedicalHistoryManageAuthorizationHandler
{
    private readonly IMedicalHistoryRepository _medicalHistoryRepository;
    private readonly IDoctorRepository _doctorRepository;
    private readonly IMedicalHistoryMongoDbService _medicalHistoryMongoDbService;

    public MedicalHistoryManageAuthorizationHandler(IMedicalHistoryRepository medicalHistoryRepository,
        IMedicalHistoryMongoDbService medicalHistoryMongoDbService, IDoctorRepository doctorRepository)
    {
        _medicalHistoryRepository = medicalHistoryRepository;
        _medicalHistoryMongoDbService = medicalHistoryMongoDbService;
        _doctorRepository = doctorRepository;
    }

    public async Task<BaseResponse> HandleGrantDoctorAccess(MedicalHistoryManageAuthorizationDoctorDto infoDto)
    {
        var validation = new MedicalHistoryManageAuthorizationValidation(_medicalHistoryRepository, _doctorRepository);
        var validationResult = await validation.ValidateAsync(infoDto);

        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
            };
        }

        var criteria = new List<(string, string)>();
        criteria.Add(("_id", infoDto.MedicalRecordId.ToString()));

        var documents = await _medicalHistoryMongoDbService.FindAsync<MedicalHistoryAuthorisationModel>(criteria);
        if (!documents.Any())
        {
            return new BaseResponse()
            {
                StatusCode = HttpStatusCodes.NotFound,
                Message = "Access to medical history not found.",
                Data = null
            };
        }
        
        var authorisations = documents[0].Authorisation;
        if (authorisations.Contains(infoDto.ToString()))
        {
            return new BaseResponse()
            {
                StatusCode = HttpStatusCodes.Conflict,
                Message = "Access to medical history already granted.",
                Data = null
            };
        }
        
        authorisations.Add(infoDto.DoctorId.ToString());
        var authorizationModel = new MedicalHistoryAuthorisationModel()
        {
            Id = infoDto.MedicalRecordId.ToString(),
            Authorisation = authorisations
        };

        await _medicalHistoryMongoDbService.ModifyAsync("_id", infoDto.MedicalRecordId.ToString(), authorizationModel);

        return new BaseResponse()
        {
            StatusCode = HttpStatusCodes.OK,
            Message = "Access to medical history granted.",
            Data = null
        };
    }

    public async Task<BaseResponse> HandleRevokeDoctorAccess(MedicalHistoryManageAuthorizationDoctorDto infoDto)
    {
        var validation = new MedicalHistoryManageAuthorizationValidation(_medicalHistoryRepository, _doctorRepository);
        var validationResult = await validation.ValidateAsync(infoDto);

        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
            };
        }

        var criteria = new List<(string, string)>();
        criteria.Add(("_id", infoDto.MedicalRecordId.ToString()));

        var documents = await _medicalHistoryMongoDbService.FindAsync<MedicalHistoryAuthorisationModel>(criteria);
        if (!documents.Any())
        {
            return new BaseResponse()
            {
                StatusCode = HttpStatusCodes.NotFound,
                Message = "Access to medical history not found.",
                Data = null
            };
        }
        
        var authorisations = documents[0].Authorisation;
        if (!authorisations.Contains(infoDto.DoctorId.ToString()))
        {
            return new BaseResponse()
            {
                StatusCode = HttpStatusCodes.Conflict,
                Message = "Access to medical history already revoked.",
                Data = null
            };
        }
        
        authorisations.Remove(infoDto.DoctorId.ToString());
        var authorizationModel = new MedicalHistoryAuthorisationModel()
        {
            Id = infoDto.MedicalRecordId.ToString(),
            Authorisation = authorisations
        };

        await _medicalHistoryMongoDbService.ModifyAsync("_id", infoDto.MedicalRecordId.ToString(), authorizationModel);

        return new BaseResponse()
        {
            StatusCode = HttpStatusCodes.OK,
            Message = "Access to medical history granted.",
            Data = null
        };
    }
}