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<Query, Result<Response>>
{
    public async Task<Result<Response>> 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));
    }
}