using CMSMicroservice.Application.Common.Interfaces;
using CMSMicroservice.Domain.Entities;
using CMSMicroservice.Domain.Entities.Commission;
using CMSMicroservice.Domain.Entities.History;
using CMSMicroservice.Domain.Enums;
using Microsoft.Extensions.Logging;

namespace CMSMicroservice.Application.CommissionCQ.Commands.BulkCreditPayouts;

public class BulkCreditPayoutsCommandHandler : IRequestHandler<BulkCreditPayoutsCommand, BulkCreditPayoutsResult>
{
    private readonly IApplicationDbContext _context;
    private readonly ICurrentUserService _currentUser;
    private readonly ILogger<BulkCreditPayoutsCommandHandler> _logger;

    public BulkCreditPayoutsCommandHandler(
        IApplicationDbContext context,
        ICurrentUserService currentUser,
        ILogger<BulkCreditPayoutsCommandHandler> logger)
    {
        _context = context;
        _currentUser = currentUser;
        _logger = logger;
    }

    public async Task<BulkCreditPayoutsResult> Handle(BulkCreditPayoutsCommand request, CancellationToken cancellationToken)
    {
        // بارگذاری همه پرداخت‌های Pending این هفته
        var pendingPayouts = await _context.UserCommissionPayouts
            .Where(p => p.WeekDefinitionId == request.WeekDefinitionId
                     && p.Status == CommissionPayoutStatus.Pending
                     && !p.IsDeleted)
            .ToListAsync(cancellationToken);

        if (!pendingPayouts.Any())
        {
            return new BulkCreditPayoutsResult { CreditedCount = 0, TotalCredited = 0 };
        }

        // بارگذاری کیف پول همه کاربران مربوطه (یک query)
        var userIds = pendingPayouts.Select(p => p.UserId).Distinct().ToList();
        var wallets = await _context.UserWallets
            .Where(w => userIds.Contains(w.UserId) && !w.IsDeleted)
            .ToDictionaryAsync(w => w.UserId, cancellationToken);

        var performedBy = _currentUser.GetPerformedBy() ?? "System";
        var now = DateTime.UtcNow;

        var walletHistories = new List<UserWalletHistory>();
        var payoutHistories = new List<CommissionPayoutHistory>();
        var creditedCount = 0;
        long totalCredited = 0;

        foreach (var payout in pendingPayouts)
        {
            if (!wallets.TryGetValue(payout.UserId, out var wallet))
            {
                _logger.LogWarning(
                    "Wallet not found for UserId={UserId}, PayoutId={PayoutId} — skipping",
                    payout.UserId, payout.Id);
                continue;
            }

            var oldBalance = wallet.Balance;

            // واریز مبلغ به کیف پول
            wallet.Balance += payout.TotalAmount;

            walletHistories.Add(new UserWalletHistory
            {
                WalletId = wallet.Id,
                CurrentBalance = wallet.Balance,
                CurrentNetworkBalance = wallet.NetworkBalance,
                CurrentDiscountBalance = wallet.DiscountBalance,
                ChangeValue = payout.TotalAmount,
                ChangeNerworkValue = 0,
                ChangeDiscountValue = 0,
                IsIncrease = true,
                RefrenceId = payout.Id
            });

            // به‌روزرسانی وضعیت پرداخت
            payout.Status = CommissionPayoutStatus.Paid;
            payout.PaidAt = now;
            payout.LastModified = now;

            payoutHistories.Add(new CommissionPayoutHistory
            {
                UserCommissionPayoutId = payout.Id,
                UserId = payout.UserId,
                WeekDefinitionId = payout.WeekDefinitionId,
                AmountBefore = 0,
                AmountAfter = payout.TotalAmount,
                OldStatus = CommissionPayoutStatus.Pending,
                NewStatus = CommissionPayoutStatus.Paid,
                Action = CommissionPayoutAction.Paid,
                PerformedBy = performedBy,
                Reason = $"واریز دسته‌جمعی کمیسیون هفته {payout.WeekDefinitionId} توسط {performedBy}"
            });

            creditedCount++;
            totalCredited += payout.TotalAmount;
        }

        await _context.UserWalletHistories.AddRangeAsync(walletHistories, cancellationToken);
        await _context.CommissionPayoutHistories.AddRangeAsync(payoutHistories, cancellationToken);
        await _context.SaveChangesAsync(cancellationToken);

        _logger.LogInformation(
            "BulkCreditPayouts completed: Week={WeekId}, Credited={Count}, TotalAmount={Total}, By={By}",
            request.WeekDefinitionId, creditedCount, totalCredited, performedBy);

        return new BulkCreditPayoutsResult
        {
            CreditedCount = creditedCount,
            TotalCredited = totalCredited
        };
    }
}
