using CMSMicroservice.Application.Common; using CMSMicroservice.Application.Common.Exceptions; using CMSMicroservice.Application.Common.Interfaces; using CMSMicroservice.Application.Common.Models; using CMSMicroservice.Domain.Entities; using CMSMicroservice.Domain.Entities.Payment; using MediatR; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; namespace CMSMicroservice.Application.WalletCQ.Commands.ChargeCreditWallet; public class ChargeCreditWalletCommandHandler : IRequestHandler { private readonly IApplicationDbContext _context; private readonly IPaymentGatewayService _paymentGateway; private readonly IConfiguration _configuration; private readonly ILogger _logger; private readonly IUserPaymentLock _paymentLock; public ChargeCreditWalletCommandHandler( IApplicationDbContext context, IPaymentGatewayService paymentGateway, IConfiguration configuration, ILogger logger, IUserPaymentLock paymentLock) { _context = context; _paymentGateway = paymentGateway; _configuration = configuration; _logger = logger; _paymentLock = paymentLock; } public Task Handle( ChargeCreditWalletCommand request, CancellationToken cancellationToken) => _paymentLock.ExecuteAsync( PaymentLockScopes.Initiate(request.UserId), PaymentLockStrategy.FailFast, ct => HandleCore(request, ct), cancellationToken); private async Task HandleCore( ChargeCreditWalletCommand request, CancellationToken cancellationToken) { try { _logger.LogInformation( "Charging credit wallet for UserId: {UserId}, Amount: {Amount}", request.UserId, request.Amount); var user = await _context.Users .Include(u => u.ClubMembership) .FirstOrDefaultAsync(u => u.Id == request.UserId, cancellationToken) ?? throw new NotFoundException(nameof(User), request.UserId); if (user.ClubMembership?.IsActive != true) { throw new BadRequestException( "برای شارژ کیف پول اصلی ابتدا باید پکیج را خریداری کرده و قرارداد باشگاه مشتریان را امضا کنید."); } var wallet = await _context.UserWallets .FirstOrDefaultAsync(w => w.UserId == request.UserId, cancellationToken) ?? throw new NotFoundException("کیف پول کاربر یافت نشد"); var frontOfficeBaseUrl = _configuration["FrontOfficeBaseUrl"] ?? "https://localhost:5268"; var callbackUrl = $"{frontOfficeBaseUrl}/profile/payment-callback?type=credit-wallet"; var paymentRequest = new PaymentRequest { Amount = request.Amount, UserId = user.Id, Mobile = user.Mobile ?? "", CallbackUrl = callbackUrl, Description = $"شارژ کیف پول اصلی - کاربر {user.Id}" }; var paymentResult = await _paymentGateway.InitiatePaymentAsync(paymentRequest); if (!paymentResult.IsSuccess) { _logger.LogError( "Payment gateway failed for UserId {UserId}: {ErrorMessage}", user.Id, paymentResult.ErrorMessage); throw new Exception($"خطا در ارتباط با درگاه پرداخت: {paymentResult.ErrorMessage}"); } var paymentTx = new PaymentTransaction { GatewayProvider = _configuration["PaymentProvider"] ?? "zarinpal", MerchantId = _configuration["ZarinPal:MerchantId"] ?? "", Amount = request.Amount, CallbackUrl = callbackUrl, Description = $"شارژ کیف پول اصلی - کاربر {user.Id}", Mobile = user.Mobile, UserId = user.Id, RequestStatusCode = 100, RequestStatusMessage = "Success", Authority = paymentResult.RefId, PaymentStatus = false }; _context.PaymentTransactions.Add(paymentTx); await _context.SaveChangesAsync(cancellationToken); _logger.LogInformation( "Credit wallet charge initiated. UserId: {UserId}, RefId: {RefId}, PaymentTxId: {PaymentTxId}", user.Id, paymentResult.RefId, paymentTx.Id); return paymentResult; } catch (Exception ex) { _logger.LogError( ex, "Error in ChargeCreditWalletCommand for UserId: {UserId}", request.UserId); throw; } } }