using CMSMicroservice.Application.Common.Exceptions; using CMSMicroservice.Application.Common.Interfaces; using CMSMicroservice.Application.Common.Models; using CMSMicroservice.Domain.Entities; using CMSMicroservice.Domain.Enums; using MediatR; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; namespace CMSMicroservice.Application.WalletCQ.Commands.VerifyDiscountWalletCharge; public class VerifyDiscountWalletChargeCommandHandler : IRequestHandler { private readonly IApplicationDbContext _context; private readonly IPaymentGatewayService _paymentGateway; private readonly ILogger _logger; public VerifyDiscountWalletChargeCommandHandler( IApplicationDbContext context, IPaymentGatewayService paymentGateway, ILogger logger) { _context = context; _paymentGateway = paymentGateway; _logger = logger; } public async Task Handle( VerifyDiscountWalletChargeCommand request, CancellationToken cancellationToken) { try { _logger.LogInformation( "Verifying discount wallet charge. UserId: {UserId}, Amount: {Amount}, Authority: {Authority}", request.UserId, request.Amount, request.Authority ); // 1. بررسی کاربر var user = await _context.Users .FirstOrDefaultAsync(u => u.Id == request.UserId, cancellationToken); if (user == null) { _logger.LogWarning("User not found: {UserId}", request.UserId); throw new NotFoundException(nameof(User), request.UserId); } // واکشی PaymentTransaction برای گرفتن مبلغ (تومان) جهت verify var paymentTx = await _context.PaymentTransactions .FirstOrDefaultAsync(pt => pt.Authority == request.Authority, cancellationToken); var amountInToman = (decimal)(paymentTx?.Amount ?? 0); // 2. Verify با درگاه (مبلغ به تومان — تبدیل به ریال در ZarinPalService) var verifyResult = await _paymentGateway.VerifyPaymentAsync( request.Authority, "OK", // وقتی این handler فراخوانی میشه یعنی کاربر از درگاه برگشته — Status باید OK باشه amountInToman, cancellationToken ); if (paymentTx != null) { paymentTx.PaymentStatus = verifyResult.IsSuccess; paymentTx.VerificationStatusCode = verifyResult.VerificationCode; paymentTx.VerificationStatusMessage = verifyResult.Message; paymentTx.CardPan = verifyResult.CardPan; paymentTx.CardHash = verifyResult.CardHash; paymentTx.RefId = verifyResult.TrackingCode; } if (!verifyResult.IsSuccess) { _logger.LogWarning( "Discount wallet charge verification failed for UserId {UserId}: {Message}", request.UserId, verifyResult.Message ); throw new Exception($"تراکنش ناموفق: {verifyResult.Message}"); } // 3. شارژ DiscountBalance var wallet = await _context.UserWallets .FirstOrDefaultAsync(w => w.UserId == user.Id, cancellationToken); if (wallet == null) { _logger.LogError("Wallet not found for UserId: {UserId}", request.UserId); throw new NotFoundException($"کیف پول کاربر با شناسه {request.UserId} یافت نشد"); } var oldBalance = wallet.DiscountBalance; wallet.DiscountBalance += request.Amount; _logger.LogInformation( "Charging discount balance for UserId {UserId}: {OldBalance} -> {NewBalance}", request.UserId, oldBalance, wallet.DiscountBalance ); // 4. ثبت Transaction var transaction = new Transaction { Amount = request.Amount, Description = $"شارژ کیف پول تخفیفی - کاربر {user.Id}", PaymentStatus = PaymentStatus.Success, PaymentDate = DateTime.Now, RefId = verifyResult.RefId, Type = TransactionType.DiscountWalletCharge }; _context.Transactions.Add(transaction); await _context.SaveChangesAsync(cancellationToken); // ثبت لاگ تغییرات کیف پول (بعد از ایجاد Transaction برای داشتن TransactionId) _context.UserWalletHistories.Add(new Domain.Entities.UserWalletHistory { WalletId = wallet.Id, CurrentBalance = wallet.Balance, ChangeValue = 0, CurrentNetworkBalance = wallet.NetworkBalance, ChangeNerworkValue = 0, CurrentDiscountBalance = wallet.DiscountBalance, ChangeDiscountValue = request.Amount, IsIncrease = true, RefrenceId = transaction.Id }); await _context.SaveChangesAsync(cancellationToken); // لینک PaymentTransaction به Transaction داخلی if (paymentTx != null) { paymentTx.TransactionId = transaction.Id; await _context.SaveChangesAsync(cancellationToken); } _logger.LogInformation( "Discount wallet charged successfully. UserId: {UserId}, TransactionId: {TransactionId}, RefId: {RefId}", user.Id, transaction.Id, verifyResult.RefId ); return true; } catch (Exception ex) { _logger.LogError( ex, "Error in VerifyDiscountWalletChargeCommand for UserId: {UserId}", request.UserId ); throw; } } }