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.VerifyGoldenPackagePurchase;

public class VerifyGoldenPackagePurchaseCommandHandler : IRequestHandler<VerifyGoldenPackagePurchaseCommand, VerifyGoldenPackagePurchaseResponseDto>
{
    private readonly IApplicationDbContext _context;
    private readonly IPaymentGatewayService _paymentGateway;
    private readonly ILogger<VerifyGoldenPackagePurchaseCommandHandler> _logger;

    public VerifyGoldenPackagePurchaseCommandHandler(
        IApplicationDbContext context,
        IPaymentGatewayService paymentGateway,
        ILogger<VerifyGoldenPackagePurchaseCommandHandler> logger)
    {
        _context = context;
        _paymentGateway = paymentGateway;
        _logger = logger;
    }

    public async Task<VerifyGoldenPackagePurchaseResponseDto> Handle(VerifyGoldenPackagePurchaseCommand request, CancellationToken cancellationToken)
    {
        try
        {
            _logger.LogInformation(
                "Verifying golden package purchase. OrderId: {OrderId}, Authority: {Authority}, Status: {Status}",
                request.OrderId,
                request.Authority,
                request.Status);

            // 1. اگر پرداخت از سمت درگاه موفق گزارش نشده باشد
            if (!string.Equals(request.Status, "OK", StringComparison.OrdinalIgnoreCase))
            {
                var pendingOrder = await _context.UserOrders
                    .FirstOrDefaultAsync(o => o.Id == request.OrderId, cancellationToken);

                if (pendingOrder != null && pendingOrder.PaymentStatus == PaymentStatus.Pending)
                {
                    pendingOrder.PaymentStatus = PaymentStatus.Reject;
                    await _context.SaveChangesAsync(cancellationToken);
                }

                throw new ValidationException("پرداخت توسط کاربر لغو شد.");
            }

            // 2. پیدا کردن سفارش به همراه کاربر
            var order = await _context.UserOrders
                .Include(o => o.User)
                .FirstOrDefaultAsync(o => o.Id == request.OrderId, cancellationToken);

            if (order == null)
            {
                _logger.LogWarning("Golden package order not found. OrderId: {OrderId}", request.OrderId);
                throw new NotFoundException(nameof(UserOrder), request.OrderId);
            }

            // اگر قبلاً با موفقیت پرداخت شده، پاسخ idempotent برگردانیم
            if (order.PaymentStatus == PaymentStatus.Success && order.TransactionId.HasValue)
            {
                var existingWallet = await _context.UserWallets
                    .FirstOrDefaultAsync(w => w.UserId == order.UserId, cancellationToken);

                var existingTransaction = await _context.Transactions
                    .FirstOrDefaultAsync(t => t.Id == order.TransactionId.Value, cancellationToken);

                return new VerifyGoldenPackagePurchaseResponseDto
                {
                    Success = true,
                    Message = "پرداخت قبلاً با موفقیت تایید شده است.",
                    OrderId = order.Id,
                    TransactionId = existingTransaction?.Id ?? order.TransactionId.Value,
                    ReferenceCode = existingTransaction?.RefId ?? string.Empty,
                    WalletBalance = existingWallet?.Balance ?? 0
                };
            }

            // 3. Verify با درگاه پرداخت
            var verifyResult = await _paymentGateway.VerifyPaymentAsync(
                request.Authority,
                request.Authority,
                cancellationToken);

            if (!verifyResult.IsSuccess)
            {
                _logger.LogWarning(
                    "Golden package payment verification failed. OrderId: {OrderId}, Message: {Message}",
                    request.OrderId,
                    verifyResult.Message);

                order.PaymentStatus = PaymentStatus.Reject;
                await _context.SaveChangesAsync(cancellationToken);

                throw new ValidationException($"تراکنش ناموفق: {verifyResult.Message}");
            }

            // 4. شارژ کیف پول (Balance فقط طبق سناریوی پکیج)
            var wallet = await _context.UserWallets
                .FirstOrDefaultAsync(w => w.UserId == order.UserId, cancellationToken);

            if (wallet == null)
            {
                _logger.LogError("Wallet not found for UserId: {UserId}", order.UserId);
                throw new NotFoundException($"کیف پول کاربر با شناسه {order.UserId} یافت نشد");
            }

            var oldBalance = wallet.Balance;
            wallet.Balance += order.Amount;

            _logger.LogInformation(
                "Charging wallet Balance for user {UserId} from {OldBalance} to {NewBalance}",
                order.UserId,
                oldBalance,
                wallet.Balance);

            // 5. ثبت Transaction
            var transaction = new Transaction
            {
                Amount = order.Amount,
                Description = $"خرید پکیج طلایی از درگاه - سفارش #{order.Id}",
                PaymentStatus = PaymentStatus.Success,
                PaymentDate = DateTime.Now,
                RefId = verifyResult.RefId,
                Type = TransactionType.DepositIpg
            };

            _context.Transactions.Add(transaction);
            await _context.SaveChangesAsync(cancellationToken);

            // 6. ثبت لاگ تغییر کیف پول
            var changeLog = new UserWalletChangeLog
            {
                WalletId = wallet.Id,
                CurrentBalance = wallet.Balance,
                ChangeValue = order.Amount,
                CurrentNetworkBalance = wallet.NetworkBalance,
                ChangeNerworkValue = 0,
                CurrentDiscountBalance = wallet.DiscountBalance,
                ChangeDiscountValue = 0,
                IsIncrease = true,
                RefrenceId = transaction.Id
            };

            await _context.UserWalletChangeLogs.AddAsync(changeLog, cancellationToken);

            // 7. به‌روزرسانی سفارش و کاربر
            order.TransactionId = transaction.Id;
            order.PaymentStatus = PaymentStatus.Success;
            order.PaymentDate = DateTime.Now;
            order.PaymentMethod = PaymentMethod.IPG;
            order.User.PackagePurchaseMethod = PackagePurchaseMethod.DirectPurchase;

            await _context.SaveChangesAsync(cancellationToken);

            _logger.LogInformation(
                "Golden package purchase verified successfully. OrderId: {OrderId}, UserId: {UserId}, TransactionId: {TransactionId}, RefId: {RefId}",
                order.Id,
                order.UserId,
                transaction.Id,
                verifyResult.RefId);

            return new VerifyGoldenPackagePurchaseResponseDto
            {
                Success = true,
                Message = "پرداخت با موفقیت تایید شد. کیف پول شما شارژ گردید.",
                OrderId = order.Id,
                TransactionId = transaction.Id,
                ReferenceCode = verifyResult.RefId,
                WalletBalance = wallet.Balance
            };
        }
        catch (Exception ex)
        {
            _logger.LogError(
                ex,
                "Error in VerifyGoldenPackagePurchaseCommand. OrderId: {OrderId}",
                request.OrderId);
            throw;
        }
    }
}
