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.Configuration; using Microsoft.Extensions.Logging; using ValidationException = FluentValidation.ValidationException; namespace CMSMicroservice.Application.PackageCQ.Commands.PurchasePackage; public class PurchasePackageCommandHandler : IRequestHandler { private readonly IApplicationDbContext _context; private readonly IPaymentGatewayService _paymentGateway; private readonly IConfiguration _configuration; private readonly ILogger _logger; public PurchasePackageCommandHandler( IApplicationDbContext context, IPaymentGatewayService paymentGateway, IConfiguration configuration, ILogger logger) { _context = context; _paymentGateway = paymentGateway; _configuration = configuration; _logger = logger; } public async Task Handle( PurchasePackageCommand request, CancellationToken cancellationToken) { try { _logger.LogInformation( "Starting package purchase for UserId: {UserId}", request.UserId ); // 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); } // 2. بررسی اینکه قبلاً پکیج نخریده باشد if (user.PackagePurchaseMethod != PackagePurchaseMethod.None) { _logger.LogWarning( "User {UserId} has already purchased package via {Method}", request.UserId, user.PackagePurchaseMethod ); throw new ValidationException( "شما قبلاً پکیج را خریداری کرده‌اید" ); } // 3. پیدا کردن پکیج (فعلاً پکیج طلایی) var goldenPackage = await _context.Packages .FirstOrDefaultAsync( p => p.Title.Contains("طلایی") || p.Title.Contains("Golden"), cancellationToken ); if (goldenPackage == null) { _logger.LogError("Package not found in database"); throw new NotFoundException("پکیج یافت نشد"); } // 4. پیدا کردن آدرس پیش‌فرض کاربر (برای فیلد اجباری) 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}", request.UserId); throw new ValidationException( "لطفاً ابتدا یک آدرس برای خود ثبت کنید" ); } // 5. ایجاد سفارش var order = new UserOrder { UserId = user.Id, PackageId = goldenPackage.Id, Amount = goldenPackage.Price, // 56,000,000 تومان PaymentStatus = PaymentStatus.Pending, DeliveryStatus = DeliveryStatus.None, UserAddressId = defaultAddress.Id, PaymentMethod = PaymentMethod.IPG }; _context.UserOrders.Add(order); await _context.SaveChangesAsync(cancellationToken); _logger.LogInformation( "Created 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 ?? "", CallbackUrl = $"{_configuration["CmsBaseUrl"] ?? "https://localhost:32846"}/api/package/verify-package", Description = $"خرید پکیج - سفارش #{order.Id}" }; var paymentResult = await _paymentGateway.InitiatePaymentAsync(paymentRequest); if (!paymentResult.IsSuccess) { _logger.LogError( "Payment gateway failed for OrderId {OrderId}: {ErrorMessage}", order.Id, paymentResult.ErrorMessage ); // به‌روزرسانی وضعیت سفارش order.PaymentStatus = PaymentStatus.Reject; await _context.SaveChangesAsync(cancellationToken); throw new Exception( $"خطا در ارتباط با درگاه پرداخت: {paymentResult.ErrorMessage}" ); } _logger.LogInformation( "Payment initiated successfully. OrderId: {OrderId}, RefId: {RefId}", order.Id, paymentResult.RefId ); return paymentResult; } catch (Exception ex) { _logger.LogError( ex, "Error in PurchasePackageCommand for UserId: {UserId}", request.UserId ); throw; } } }