// src/Webshop.Application/Services/Admin/AdminAnalyticsService.cs using Microsoft.EntityFrameworkCore; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Webshop.Application.DTOs.Admin; using Webshop.Application.Services.Admin.Interfaces; using Webshop.Domain.Enums; using Webshop.Domain.Interfaces; using Webshop.Infrastructure.Data; namespace Webshop.Application.Services.Admin { public class AdminAnalyticsService : IAdminAnalyticsService { private readonly ApplicationDbContext _context; private readonly ISettingService _settingService; public AdminAnalyticsService(ApplicationDbContext context, ISettingService settingService) { _context = context; _settingService = settingService; } public async Task GetAnalyticsAsync(AnalyticsPeriod period) { var startDate = GetStartDateFromPeriod(period); var filteredOrders = await _context.Orders .Where(o => o.OrderDate >= startDate && o.OrderStatus != OrderStatus.Cancelled.ToString()) .ToListAsync(); var analyticsDto = new AnalyticsDto { KpiSummary = await GetKpiSummaryAsync(startDate, filteredOrders), SalesOverTime = GetSalesOverTime(filteredOrders), TopPerformingProducts = await GetTopPerformingProductsAsync(startDate), InventoryStatus = await GetInventoryStatusAsync() }; return analyticsDto; } private async Task GetKpiSummaryAsync(DateTimeOffset startDate, List filteredOrders) { var totalRevenue = filteredOrders.Sum(o => o.OrderTotal); var totalOrders = filteredOrders.Count; return new KpiSummaryDto { TotalRevenue = totalRevenue, TotalOrders = totalOrders, TotalCustomers = await _context.Customers.CountAsync(), NewCustomersThisPeriod = await _context.Users.CountAsync(u => u.CreatedDate >= startDate), AverageOrderValue = totalOrders > 0 ? totalRevenue / totalOrders : 0 }; } private List GetSalesOverTime(List orders) { return orders .GroupBy(o => o.OrderDate.Date) .Select(g => new SalesDataPointDto { Date = g.Key.ToString("yyyy-MM-dd"), Revenue = g.Sum(o => o.OrderTotal) }) .OrderBy(dp => dp.Date) .ToList(); } private async Task> GetTopPerformingProductsAsync(DateTimeOffset startDate) { return await _context.OrderItems .Where(oi => oi.Order.OrderDate >= startDate && oi.ProductId.HasValue) .GroupBy(oi => new { oi.ProductId, oi.ProductName, oi.ProductSKU }) .Select(g => new TopProductDto { ProductId = g.Key.ProductId!.Value, Name = g.Key.ProductName, Sku = g.Key.ProductSKU, UnitsSold = g.Sum(oi => oi.Quantity), TotalRevenue = g.Sum(oi => oi.TotalPrice) }) .OrderByDescending(p => p.UnitsSold) .Take(10) .ToListAsync(); } private async Task GetInventoryStatusAsync() { var lowStockThreshold = await _settingService.GetSettingValueAsync("LowStockThreshold", 10); var totalProducts = await _context.Products.CountAsync(p => p.IsActive); var productsInStock = await _context.Products.CountAsync(p => p.IsActive && p.StockQuantity > 0); var productsWithLowStock = await _context.Products.CountAsync(p => p.IsActive && p.StockQuantity > 0 && p.StockQuantity <= lowStockThreshold); return new InventoryStatusDto { ProductsWithLowStock = productsWithLowStock, OverallStockAvailabilityPercentage = totalProducts > 0 ? Math.Round((double)productsInStock / totalProducts * 100, 2) : 0 }; } private DateTimeOffset GetStartDateFromPeriod(AnalyticsPeriod period) { return period switch { AnalyticsPeriod.Last7Days => DateTimeOffset.UtcNow.AddDays(-7), AnalyticsPeriod.Last30Days => DateTimeOffset.UtcNow.AddDays(-30), _ => DateTimeOffset.MinValue }; } } }