using CMSMicroservice.Application.Common.Exceptions;
using CMSMicroservice.Application.Common.Interfaces;
using CMSMicroservice.Domain.Entities;
using CMSMicroservice.Domain.Enums;
using CMSMicroservice.Domain.Common;
using MediatR;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;

namespace CMSMicroservice.Application.PackageCQ.Commands.VerifyBasePackagePayment;

/// <summary>
/// Handler برای تکمیل یا رد پرداخت پکیج پایه
/// فراخوانی توسط BFF بعد از اینکه نتیجه Verify از PYMS مشخص شد
/// 
/// اگر PaymentSuccess = true:
/// - شارژ کیف پول (Balance + DiscountBalance)
/// - ثبت لاگ تغییر کیف پول
/// - به‌روزرسانی سفارش و کاربر
/// 
/// اگر PaymentSuccess = false:
/// - فقط آپدیت وضعیت تراکنش و سفارش به Reject
/// </summary>
public class VerifyBasePackagePaymentCommandHandler : IRequestHandler<VerifyBasePackagePaymentCommand, VerifyBasePackagePaymentResponseDto>
{
    private readonly IApplicationDbContext _context;
    private readonly ILogger<VerifyBasePackagePaymentCommandHandler> _logger;

    public VerifyBasePackagePaymentCommandHandler(
        IApplicationDbContext context,
        ILogger<VerifyBasePackagePaymentCommandHandler> logger)
    {
        _context = context;
        _logger = logger;
    }

    public async Task<VerifyBasePackagePaymentResponseDto> Handle(
        VerifyBasePackagePaymentCommand request, 
        CancellationToken cancellationToken)
    {
        try
        {
            _logger.LogInformation(
                "Processing base package payment result. OrderId: {OrderId}, TransactionId: {TransactionId}, PaymentSuccess: {PaymentSuccess}",
                request.OrderId,
                request.TransactionId,
                request.PaymentSuccess);

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

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

            // 2. پیدا کردن تراکنش
            var transaction = await _context.Transactions
                .FirstOrDefaultAsync(t => t.Id == request.TransactionId, cancellationToken);

            if (transaction == null)
            {
                _logger.LogWarning("Transaction not found. TransactionId: {TransactionId}", request.TransactionId);
                throw new NotFoundException(nameof(Transaction), request.TransactionId);
            }

            // 3. بررسی Idempotency - اگر قبلاً تایید شده باشد
            if (order.PaymentStatus == PaymentStatus.Success)
            {
                _logger.LogInformation(
                    "Order {OrderId} already verified successfully",
                    request.OrderId);

                var existingWallet = await _context.UserWallets
                    .FirstOrDefaultAsync(w => w.UserId == order.UserId, cancellationToken);

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

            // 4. اگر پرداخت ناموفق بود - فقط وضعیت را Reject می‌کنیم
            if (!request.PaymentSuccess)
            {
                _logger.LogWarning(
                    "Payment failed. OrderId: {OrderId}, Message: {Message}",
                    request.OrderId,
                    request.Message);

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

                return new VerifyBasePackagePaymentResponseDto
                {
                    Success = false,
                    Message = request.Message ?? "پرداخت ناموفق بود.",
                    OrderId = order.Id,
                    TransactionId = transaction.Id
                };
            }

            // 5. پرداخت موفق - پیدا کردن یا ایجاد کیف پول
            var userWallet = await _context.UserWallets
                .FirstOrDefaultAsync(w => w.UserId == order.UserId, cancellationToken);

            if (userWallet == null)
            {
                _logger.LogInformation("Creating new wallet for UserId: {UserId}", order.UserId);
                userWallet = new UserWallet
                {
                    UserId = order.UserId,
                    Balance = 0,
                    DiscountBalance = 0,
                    NetworkBalance = 0
                };
                _context.UserWallets.Add(userWallet);
                await _context.SaveChangesAsync(cancellationToken);
            }

            // 6. شارژ کیف پول (هم Balance و هم DiscountBalance)
            var oldBalance = userWallet.Balance;
            var oldDiscountBalance = userWallet.DiscountBalance;
            
            userWallet.Balance += SystemConstants.BasePackageAmount;
            userWallet.DiscountBalance += SystemConstants.BasePackageAmount;

            _logger.LogInformation(
                "Charging wallet for user {UserId}. Balance: {OldBalance} -> {NewBalance}, DiscountBalance: {OldDiscount} -> {NewDiscount}",
                order.UserId,
                oldBalance,
                userWallet.Balance,
                oldDiscountBalance,
                userWallet.DiscountBalance);

            // 7. به‌روزرسانی Transaction
            transaction.PaymentStatus = PaymentStatus.Success;
            transaction.PaymentDate = DateTime.Now;
            transaction.RefId = request.RefId;

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

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

            // 9. به‌روزرسانی Order
            order.TransactionId = transaction.Id;
            order.PaymentStatus = PaymentStatus.Success;
            order.PaymentDate = DateTime.Now;
            order.PaymentMethod = PaymentMethod.IPG;

            // 10. به‌روزرسانی User
            order.User.PackagePurchaseMethod = PackagePurchaseMethod.DirectPurchase;

            await _context.SaveChangesAsync(cancellationToken);

            _logger.LogInformation(
                "Base package payment completed successfully. OrderId: {OrderId}, UserId: {UserId}, TransactionId: {TransactionId}, RefId: {RefId}",
                order.Id,
                order.UserId,
                transaction.Id,
                request.RefId);

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