using Application.Abstractions.Data; using Application.Abstractions.Messaging; using Microsoft.EntityFrameworkCore; using SharedKernel.Results; namespace Application.Features.Api.Developers.Stats.UsageStats; internal sealed class Handler(IAppDbContext db) : IQueryHandler> { private const int DefaultDays = 7; private const int MaxDays = 90; public async Task> Handle(Query request, CancellationToken ct) { var days = Math.Clamp(request.Days <= 0 ? DefaultDays : request.Days, 1, MaxDays); var since = DateTime.UtcNow.AddDays(-days); // 본인 소유 앱 + 본인 PAT 만 집계 var ownedAppIDs = await db.ApiApplication .Where(c => c.OwnerMemberID == request.OwnerMemberID) .Select(c => c.ID) .ToListAsync(ct); var ownedPatIDs = await db.ApiPersonalAccessToken .Where(c => c.OwnerMemberID == request.OwnerMemberID) .Select(c => c.ID) .ToListAsync(ct); var raw = await db.ApiRequestLog .Where(c => c.RequestedAt >= since && ((c.ApplicationID != null && ownedAppIDs.Contains(c.ApplicationID.Value)) || (c.PatID != null && ownedPatIDs.Contains(c.PatID.Value)))) .GroupBy(c => new { Date = DateOnly.FromDateTime(c.RequestedAt) }) .Select(g => new DailyUsage( g.Key.Date, g.Count(), g.Count(c => c.StatusCode >= 400), (int)g.Average(c => (double)c.ResponseMs) )) .OrderBy(c => c.Date) .ToListAsync(ct); return Result.Success(new Response(raw)); } }