using System.Text.Json; using Microsoft.EntityFrameworkCore; using Tiku.Application.Jobs; using Tiku.Application.Security; using Tiku.Domain.Commerce; using Tiku.Infrastructure.Persistence; namespace Tiku.Infrastructure.TenantAdmin.Dashboard; internal sealed class StatisticsAggregationJobHandler( TikuDbContext dbContext, IFeatureUsageReconciliationService featureUsageReconciliationService) : IBackgroundJobHandler { public string JobType => "statistics_aggregation"; public async Task HandleAsync( BackgroundJobExecutionContext context, CancellationToken cancellationToken = default) { var since = DateTimeOffset.UtcNow.AddDays(-7); var activeLearnerCount = await dbContext.PracticeSessions .Where(item => item.TenantId == context.TenantId && item.StartedAt >= since) .Select(item => item.UserId) .Distinct() .CountAsync(cancellationToken); var paidOrderCount = await dbContext.Orders .CountAsync(item => item.TenantId == context.TenantId && item.Status == OrderStatus.Paid, cancellationToken); var revenueCents = await dbContext.Orders .Where(item => item.TenantId == context.TenantId && (item.Status == OrderStatus.Paid || item.Status == OrderStatus.PartiallyRefunded || item.Status == OrderStatus.Refunded)) .SumAsync(item => item.AmountCents - item.RefundedAmountCents, cancellationToken); var quotaUsage = await featureUsageReconciliationService.ReconcileTenantAsync( new ReconcileFeatureUsageRequest( context.TenantId, SystemScopeCallerType.Worker, nameof(StatisticsAggregationJobHandler), "Reconcile tenant current feature usage during statistics aggregation", $"feature-usage-{context.JobId:N}"), cancellationToken); return new BackgroundJobHandlerResult(JsonSerializer.SerializeToElement(new { since, activeLearnerCount, paidOrderCount, revenueCents, quotaUsage })); } }