using Application.Abstractions.Data; using Application.Abstractions.Messaging; using Domain.Entities.Donations.ValueObject; using Microsoft.EntityFrameworkCore; using SharedKernel.Results; namespace Application.Features.Api.Studio.Wallet.GetBalance; internal sealed class Handler(IAppDbContext db) : IQueryHandler> { private static readonly Response Empty = new(0, 0, 0, 0, []); public async Task> Handle(Query request, CancellationToken ct) { var channel = await db.Channel.AsNoTracking().FirstOrDefaultAsync(c => c.MemberID == request.MemberID && c.IsActive, ct); if (channel is null) { return Result.Success(Empty); } // Wallet Donation 잔액 var wallet = await db.Wallet.AsNoTracking() .Include(w => w.Balances) .FirstOrDefaultAsync(w => w.MemberID == request.MemberID, ct); var withdrawableBalance = 0; if (wallet is not null) { var donationBal = wallet.Balances.FirstOrDefault(b => b.Type == Domain.Entities.Wallets.ValueObject.WalletBalanceType.Donation); if (donationBal is not null) { withdrawableBalance = (int)donationBal.Amount.Value; } } // 누적 수익 (Donation NetAmount 합계) var totalEarned = await db.Donation.AsNoTracking() .Where(d => d.ReceiverMemberID == request.MemberID && !d.IsTest) .SumAsync(d => d.NetAmount, ct); // 누적 출금 (완료된 출금 합계) var totalWithdrawn = await db.WithdrawalRequest.AsNoTracking() .Where(w => w.MemberID == request.MemberID && w.Status == WithdrawalStatus.Completed) .SumAsync(w => w.NetAmount, ct); // 대기 중 출금 var pendingWithdrawal = await db.WithdrawalRequest.AsNoTracking() .Where(w => w.MemberID == request.MemberID && (w.Status == WithdrawalStatus.Pending || w.Status == WithdrawalStatus.Processing)) .SumAsync(w => w.RequestedAmount, ct); // 최근 거래 내역 10건 var recentTx = await db.WalletTransaction.AsNoTracking() .Where(t => t.Wallet!.MemberID == request.MemberID && t.BalanceType == Domain.Entities.Wallets.ValueObject.WalletBalanceType.Donation) .OrderByDescending(t => t.CreatedAt) .Take(10) .Select(t => new TransactionItem( t.ID, t.TxType.ToString(), (int)t.Amount.Value, (int)t.BalanceAfter.Value, t.Memo ?? "", t.CreatedAt )) .ToListAsync(ct); return Result.Success(new Response( withdrawableBalance, totalEarned, totalWithdrawn, pendingWithdrawal, recentTx )); } }