#nullable enable
using Baya.Application.Common;
using Baya.Application.Contracts.Common;
using Baya.Application.Contracts.Persistence;
using Baya.Application.Models.Common;
using Baya.Application.Models.Verification;
using Baya.Domain.Entities.User;
using Baya.Domain.Entities.Verification;
using Mediator;

namespace Baya.Application.Features.Verification.Commands.ConfirmDocumentUpload;

internal sealed class ConfirmDocumentUploadCommandHandler(
    ICurrentUser currentUser,
    IUnitOfWork unitOfWork,
    IDateTimeProvider dateTimeProvider)
    : IRequestHandler<ConfirmDocumentUploadCommand, OperationResult<DocumentConfirmedResult>>
{
    public async ValueTask<OperationResult<DocumentConfirmedResult>> Handle(
        ConfirmDocumentUploadCommand request, CancellationToken cancellationToken)
    {
        if (currentUser.UserId is not { } userId)
            return OperationResult<DocumentConfirmedResult>.UnauthorizedResult("Not authenticated.");

        if (currentUser.Roles?.Contains(RoleNames.Nurse) != true)
            return OperationResult<DocumentConfirmedResult>.ForbiddenResult("Only a nurse can upload verification documents.");

        var context = await unitOfWork.NurseProfileRepository.GetIdentityContextByUserIdAsync(userId, cancellationToken);
        if (context is null)
            return OperationResult<DocumentConfirmedResult>.NotFoundResult("No nurse profile exists yet.");

        var nurseId = context.NurseProfileId;
        var step = await unitOfWork.VerificationRepository.GetTrackedStepForNurseAsync(request.StepId, nurseId, cancellationToken);
        if (step is null)
            return OperationResult<DocumentConfirmedResult>.NotFoundResult("Verification step not found.");

        if (step.IsAutomated)
            return OperationResult<DocumentConfirmedResult>.FailureResult("This step is verified automatically and does not accept document uploads.");

        var now = dateTimeProvider.UtcNow;

        var document = new VerificationDocument
        {
            StepId = step.Id,
            ObjectStorageKey = request.ObjectStorageKey,
            IntegrityHash = request.IntegrityHash,
            ContentType = request.ContentType,
            FileSizeBytes = request.FileSizeBytes,
            OriginalFileName = request.OriginalFileName,
            UploadedByUserId = userId
        };
        await unitOfWork.VerificationRepository.AddDocumentAsync(document, cancellationToken);

        // A manual step with evidence attached moves into the admin review queue.
        step.Status = VerificationStepStatus.InReview;
        step.StartedAt ??= now;

        var profile = await unitOfWork.NurseProfileRepository.GetTrackedByIdAsync(nurseId, cancellationToken);
        if (profile is null)
            return OperationResult<DocumentConfirmedResult>.NotFoundResult("Nurse profile not found.");

        VerificationAggregator.Finalize(step.NurseVerification, profile, now);

        await unitOfWork.CommitAsync();

        return OperationResult<DocumentConfirmedResult>.SuccessResult(new DocumentConfirmedResult(document.Id, step.Status.ToCode()));
    }
}
