using Application.Abstractions.Data; using Application.Abstractions.Messaging; using Application.Features.Api.Studio.Helpers; using Microsoft.EntityFrameworkCore; using SharedKernel.Results; namespace Application.Features.Api.Studio.Wallet.GetRevenue; internal sealed class Handler(IAppDbContext db) : IQueryHandler> { public async Task> Handle(Query request, CancellationToken ct) { var (start, end) = PeriodHelper.GetRange(request.Period); var baseQuery = db.Donation.AsNoTracking() .Where(d => d.ReceiverMemberID == request.MemberID && !d.IsTest && d.CreatedAt >= start && d.CreatedAt <= end); // Summary var total = await baseQuery.CountAsync(ct); var grossSum = total > 0 ? await baseQuery.SumAsync(d => d.Amount, ct) : 0; var feeSum = total > 0 ? await baseQuery.SumAsync(d => d.FeeAmount, ct) : 0; var netSum = total > 0 ? await baseQuery.SumAsync(d => d.NetAmount, ct) : 0; var summary = new RevenueSummary(grossSum, feeSum, netSum); // Paged list var list = await baseQuery .OrderByDescending(d => d.CreatedAt) .Skip((request.Page - 1) * request.PerPage) .Take(request.PerPage) .Select(d => new RevenueItem( d.ID, d.SendName, d.Sponsor != null ? d.Sponsor.SID : null, d.Amount, d.FeeAmount, d.NetAmount, d.CrewSessionID != null ? "crew_donation" : "donation", d.CrewMember != null ? d.CrewMember.Nickname : null, d.CreatedAt )) .ToListAsync(ct); // Chart data — daily grouping var chartRaw = await baseQuery .GroupBy(d => d.CreatedAt.Date) .Select(g => new { Date = g.Key, GrossAmount = g.Sum(d => d.Amount), PlatformFee = g.Sum(d => d.FeeAmount), NetAmount = g.Sum(d => d.NetAmount) }) .OrderBy(x => x.Date) .ToListAsync(ct); var chartData = chartRaw.Select(c => new ChartItem(c.Date.ToString("MM/dd"), c.GrossAmount, c.PlatformFee, c.NetAmount)).ToList(); return Result.Success(new Response(total, summary, list, chartData)); } }