using Microsoft.EntityFrameworkCore; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using TaskTrackingSystem.Database.AppDbContextModels; using TaskTrackingSystem.Shared; using TaskTrackingSystem.Shared.Enums; using TaskTrackingSystem.Shared.Models.Dashboard; using TaskTrackingSystem.WebApi.Infrastructure; namespace TaskTrackingSystem.WebApi.Features.Dashboard { public class DashboardService { private readonly AppDbContext _db; public DashboardService(AppDbContext db) { _db = db; } public async Task> GetSummaryAsync(long roleId, long currentUserId) { var isAdmin = await DataScopeAuthorization.IsAdminScopeAsync(_db, roleId); var isManager = await DataScopeAuthorization.IsManagerScopeAsync(_db, roleId); var projects = BuildAccessibleProjectQuery(isAdmin, currentUserId); var tasks = BuildAccessibleTaskQuery(isAdmin, isManager, currentUserId); var totalUsers = isAdmin ? await _db.Users.CountAsync(u => !u.IsDeleted) : await _db.Users .Where(u => !u.IsDeleted && projects.SelectMany(p => p.ProjectMembers.Select(pm => pm.UserId)) .Distinct() .Contains(u.Id)) .CountAsync(); var activeProjectsCount = await projects.CountAsync(); var pendingTasksCount = await tasks.CountAsync(t => t.StatusId != AppTaskStatus.Done); var summary = new DashboardSummaryDto { TotalUsers = totalUsers, ActiveProjectsCount = activeProjectsCount, PendingTasksCount = pendingTasksCount }; return Result.Success(summary); } public async Task>> GetTasksOverviewAsync(long roleId, long currentUserId) { var isAdmin = await DataScopeAuthorization.IsAdminScopeAsync(_db, roleId); var isManager = await DataScopeAuthorization.IsManagerScopeAsync(_db, roleId); var groupedTasks = await BuildAccessibleTaskQuery(isAdmin, isManager, currentUserId) .GroupBy(t => t.StatusId) .Select(g => new { StatusId = g.Key, Count = g.Count() }) .ToListAsync(); var statusMap = new Dictionary { { AppTaskStatus.Todo, "To Do" }, { AppTaskStatus.InProgress, "In Progress" }, { AppTaskStatus.Done, "Done" } }; var overview = groupedTasks.Select(gt => new TaskStatusOverviewDto { StatusId = gt.StatusId, StatusName = statusMap.TryGetValue(gt.StatusId, out var name) ? name : $"Status {gt.StatusId}", TaskCount = gt.Count }).ToList(); foreach (var status in statusMap) { if (!overview.Any(o => o.StatusId == status.Key)) { overview.Add(new TaskStatusOverviewDto { StatusId = status.Key, StatusName = status.Value, TaskCount = 0 }); } } return Result>.Success(overview.OrderBy(o => o.StatusId)); } public async Task>> GetProjectProgressAsync(long roleId, long currentUserId) { var isAdmin = await DataScopeAuthorization.IsAdminScopeAsync(_db, roleId); var activeProjects = await BuildAccessibleProjectQuery(isAdmin, currentUserId).ToListAsync(); var progressList = new List(); foreach (var project in activeProjects) { var tasks = await _db.Tasks .Where(t => t.ProjectId == project.Id && t.IsDeleted != true && !t.IsArchived) .ToListAsync(); int totalTasks = tasks.Count; int completedTasks = tasks.Count(t => t.StatusId == AppTaskStatus.Done); double percentage = totalTasks > 0 ? Math.Round(((double)completedTasks / totalTasks) * 100, 2) : 0; progressList.Add(new ProjectProgressDto { ProjectId = project.Id, ProjectName = project.Name, TotalTasksCount = totalTasks, CompletedTasksCount = completedTasks, CompletionPercentage = percentage }); } return Result>.Success(progressList); } private IQueryable BuildAccessibleTaskQuery(bool isAdmin, bool isManager, long currentUserId) { var query = _db.Tasks.Where(t => t.IsDeleted != true && !t.IsArchived); if (isAdmin) { return query; } if (isManager) { return query.Where(t => t.AssignedTo == currentUserId || t.CreatedBy == currentUserId || t.Project.ProjectMembers.Any(pm => pm.UserId == currentUserId)); } return query.Where(t => t.AssignedTo == currentUserId || t.CreatedBy == currentUserId); } private IQueryable BuildAccessibleProjectQuery(bool isAdmin, long currentUserId) { var query = _db.Projects.Where(p => p.IsDeleted != true); if (isAdmin) { return query; } return query.Where(p => p.CreatedById == currentUserId || p.ProjectMembers.Any(pm => pm.UserId == currentUserId)); } } }