#nullable enable
using System.Text.Json;
using Baya.Application.Contracts.Common;
using Baya.Application.Contracts.Persistence;
using Baya.Application.Models.Common;
using Baya.Application.Models.Reviews;
using Baya.Domain.Entities.Reviews;
using Mediator;

namespace Baya.Application.Features.PatientCareRecords.Commands.WritePatientCareRecord;

/// <summary>
/// A nurse writes a patient-scoped clinical note. Guards: the caller is a nurse, the patient exists, and the
/// nurse has a <b>confirmed</b> (or later) booking for that patient — a nurse never assigned is denied. The
/// clinical body is encrypted through <see cref="IFieldEncryptor"/> before it is persisted; plaintext never
/// touches the column.
/// </summary>
internal sealed class WritePatientCareRecordCommandHandler(
    ICurrentUser currentUser,
    IUnitOfWork unitOfWork,
    IFieldEncryptor fieldEncryptor,
    IDateTimeProvider dateTimeProvider)
    : IRequestHandler<WritePatientCareRecordCommand, OperationResult<WriteCareRecordResult>>
{
    public async ValueTask<OperationResult<WriteCareRecordResult>> Handle(
        WritePatientCareRecordCommand request, CancellationToken cancellationToken)
    {
        if (currentUser.UserId is not { } userId)
            return OperationResult<WriteCareRecordResult>.UnauthorizedResult("Not authenticated.");

        var nurseProfileId = await unitOfWork.NurseProfileRepository.GetProfileIdByUserIdAsync(userId, cancellationToken);
        if (nurseProfileId is not { } nurseId)
            return OperationResult<WriteCareRecordResult>.ForbiddenResult("Only a nurse can write a care record.");

        var owner = await unitOfWork.PatientCareRecordRepository.GetPatientOwnerCustomerIdAsync(request.PatientId, cancellationToken);
        if (owner is null)
            return OperationResult<WriteCareRecordResult>.NotFoundResult("Patient not found.");

        var qualifies = await unitOfWork.PatientCareRecordRepository
            .NurseHasQualifyingBookingForPatientAsync(nurseId, request.PatientId, cancellationToken);
        if (!qualifies)
            return OperationResult<WriteCareRecordResult>.ForbiddenResult(
                "You can only write care records for a patient you have a confirmed booking with.");

        var record = new PatientCareRecord
        {
            PatientId = request.PatientId,
            BookingId = request.BookingId,
            NurseProfileId = nurseId,
            BodyEncrypted = fieldEncryptor.Encrypt(request.Body.Trim()),
            TaskResultsJson = request.TaskResults is { Count: > 0 } tr ? JsonSerializer.Serialize(tr) : null,
            RecordedAt = dateTimeProvider.UtcNow.UtcDateTime
        };

        await unitOfWork.PatientCareRecordRepository.AddAsync(record, cancellationToken);
        await unitOfWork.CommitAsync();

        return OperationResult<WriteCareRecordResult>.SuccessResult(
            new WriteCareRecordResult(record.Id, record.PatientId, record.RecordedAt));
    }
}
