#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.Identity;
using Baya.Domain.Entities.User;
using Mediator;

namespace Baya.Application.Features.Identity.Commands.TriggerBankAccountOwnershipInquiry;

internal sealed class TriggerBankAccountOwnershipInquiryCommandHandler(
    ICurrentUser currentUser,
    IUnitOfWork unitOfWork,
    IBankAccountOwnershipVerifier ownershipVerifier)
    : IRequestHandler<TriggerBankAccountOwnershipInquiryCommand, OperationResult<NurseBankAccountDto>>
{
    public async ValueTask<OperationResult<NurseBankAccountDto>> Handle(TriggerBankAccountOwnershipInquiryCommand request, CancellationToken cancellationToken)
    {
        if (currentUser.UserId is not { } userId)
            return OperationResult<NurseBankAccountDto>.UnauthorizedResult("Not authenticated.");

        if (currentUser.Roles?.Contains(RoleNames.Nurse) != true)
            return OperationResult<NurseBankAccountDto>.ForbiddenResult("Only a nurse can run an ownership inquiry.");

        var context = await unitOfWork.NurseProfileRepository.GetIdentityContextByUserIdAsync(userId, cancellationToken);
        if (context is null)
            return OperationResult<NurseBankAccountDto>.NotFoundResult("Bank account not found.");

        var account = await unitOfWork.NurseBankAccountRepository.GetOwnedAsync(request.Id, context.NurseProfileId, cancellationToken);
        if (account is null)
            return OperationResult<NurseBankAccountDto>.NotFoundResult("Bank account not found.");

        // The tracked entity decrypts the IBAN on materialization, so we can re-run the inquiry on it.
        var inquiry = await ownershipVerifier.VerifyOwnershipAsync(account.Iban, context.NationalId, cancellationToken);
        account.ApplyOwnershipInquiry(inquiry.MatchedNationalId, inquiry.AccountHolderFromBank, inquiry.VendorRef);

        await unitOfWork.CommitAsync();

        return OperationResult<NurseBankAccountDto>.SuccessResult(new NurseBankAccountDto(
            account.Id,
            account.BankName,
            Mask.IbanTail(account.Iban),
            account.IsPrimary,
            account.IsVerified,
            account.MatchedNationalId));
    }
}
