using CMSMicroservice.Application.Common.Exceptions; using CMSMicroservice.Application.Common.Interfaces; using CMSMicroservice.Domain.Entities; using CMSMicroservice.Domain.Enums; using MediatR; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using ValidationException = FluentValidation.ValidationException; namespace CMSMicroservice.Application.PackageCQ.Commands.PurchaseGoldenPackage; public class PurchaseGoldenPackageCommandHandler : IRequestHandler { private readonly IApplicationDbContext _context; private readonly IPaymentGatewayService _paymentGateway; private readonly ILogger _logger; public PurchaseGoldenPackageCommandHandler( IApplicationDbContext context, IPaymentGatewayService paymentGateway, ILogger logger) { _context = context; _paymentGateway = paymentGateway; _logger = logger; } public async Task Handle(PurchaseGoldenPackageCommand request, CancellationToken cancellationToken) { try { _logger.LogInformation( "Starting golden package purchase for UserId: {UserId}, PackageId: {PackageId}", request.UserId, request.PackageId); // 1. پیدا کردن کاربر var user = await _context.Users .FirstOrDefaultAsync(u => u.Id == request.UserId, cancellationToken); if (user == null) { _logger.LogWarning("User not found for golden package purchase. UserId: {UserId}", request.UserId); throw new NotFoundException(nameof(User), request.UserId); } // 2. جلوگیری از خرید مجدد پکیج طلایی if (user.PackagePurchaseMethod != PackagePurchaseMethod.None) { _logger.LogWarning( "User {UserId} has already purchased golden package via {Method}", request.UserId, user.PackagePurchaseMethod); throw new ValidationException("شما قبلاً پکیج طلایی را خریداری کرده‌اید."); } // 3. پیدا کردن پکیج var package = await _context.Packages .FirstOrDefaultAsync(p => p.Id == request.PackageId, cancellationToken); if (package == null) { _logger.LogWarning("Golden package not found. PackageId: {PackageId}", request.PackageId); throw new NotFoundException(nameof(Package), request.PackageId); } // اطمینان از فعال بودن و قابل خرید بودن پکیج if (package.IsDeleted || !package.IsActive) { _logger.LogWarning( "PackageId {PackageId} is not available. IsDeleted: {IsDeleted}, IsActive: {IsActive}", request.PackageId, package.IsDeleted, package.IsActive); throw new ValidationException("این پکیج در حال حاضر قابل خرید نیست."); } if (!package.SupportsDirectPurchase) { throw new ValidationException("این پکیج فقط از طریق وام دایا قابل خرید است."); } // 4. پیدا کردن آدرس پیش‌فرض کاربر (الزامی برای UserOrder) var defaultAddress = await _context.UserAddresses .Where(a => a.UserId == request.UserId) .OrderByDescending(a => a.Created) .FirstOrDefaultAsync(cancellationToken); if (defaultAddress == null) { _logger.LogWarning("No address found for user {UserId} in golden package purchase", request.UserId); throw new ValidationException("لطفاً ابتدا یک آدرس برای خود ثبت کنید."); } // 5. ایجاد سفارش var order = new UserOrder { UserId = user.Id, PackageId = package.Id, Amount = package.Price, PaymentStatus = PaymentStatus.Pending, DeliveryStatus = DeliveryStatus.None, UserAddressId = defaultAddress.Id, PaymentMethod = PaymentMethod.IPG }; _context.UserOrders.Add(order); await _context.SaveChangesAsync(cancellationToken); _logger.LogInformation( "Created golden package UserOrder {OrderId} for UserId {UserId}, Amount: {Amount}", order.Id, request.UserId, order.Amount); // 6. شروع پرداخت با درگاه var paymentRequest = new PaymentRequest { Amount = order.Amount, UserId = user.Id, Mobile = user.Mobile ?? string.Empty, CallbackUrl = request.ReturnUrl, Description = $"خرید پکیج طلایی - سفارش #{order.Id}" }; var paymentResult = await _paymentGateway.InitiatePaymentAsync(paymentRequest, cancellationToken); if (!paymentResult.IsSuccess) { _logger.LogError( "Payment gateway initiation failed for golden package. OrderId {OrderId}: {ErrorMessage}", order.Id, paymentResult.ErrorMessage); order.PaymentStatus = PaymentStatus.Reject; await _context.SaveChangesAsync(cancellationToken); throw new Exception($"خطا در ارتباط با درگاه پرداخت: {paymentResult.ErrorMessage}"); } _logger.LogInformation( "Golden package payment initiated successfully. OrderId: {OrderId}, RefId: {RefId}", order.Id, paymentResult.RefId); return new PurchaseGoldenPackageResponseDto { Success = true, Message = "لطفاً به درگاه پرداخت منتقل شوید.", OrderId = order.Id, PaymentGatewayUrl = paymentResult.GatewayUrl ?? string.Empty, TrackingCode = paymentResult.RefId ?? string.Empty }; } catch (Exception ex) { _logger.LogError( ex, "Error in PurchaseGoldenPackageCommand for UserId: {UserId}", request.UserId); throw; } } }