using Core.Entities; using Core.Models; using Data; using Microsoft.EntityFrameworkCore; namespace WebApp.Services; /// /// Replaces event rankings for students present in a successful ranking import. /// public class StudentEventRankingSaveService : IStudentEventRankingSaveService { private readonly AppDbContext _context; private readonly ILogger _logger; public StudentEventRankingSaveService(AppDbContext context, ILogger logger) { _context = context; _logger = logger; } /// public async Task> GetStudentsWithExistingRankingsAsync( StudentEventRankingParseResult parseResult, CancellationToken cancellationToken = default) { var studentIds = GetStudentIds(parseResult); if (studentIds.Count == 0) return []; return await _context.Students .AsNoTracking() .Where(s => studentIds.Contains(s.Id) && s.EventRankings.Any()) .OrderBy(s => s.LastName) .ThenBy(s => s.FirstName) .Select(s => s.FirstName + " " + s.LastName) .ToListAsync(cancellationToken); } /// public async Task SaveAsync( StudentEventRankingParseResult parseResult, CancellationToken cancellationToken = default) { var studentIds = GetStudentIds(parseResult); if (studentIds.Count == 0) return new StudentEventRankingSaveResult(); var students = await _context.Students .Include(s => s.EventRankings) .Where(s => studentIds.Contains(s.Id)) .ToListAsync(cancellationToken); var eventIds = parseResult.Matches .Select(m => m.Ranking.EventDefinition.Id) .Where(id => id != 0) .Distinct() .ToList(); var events = await _context.Events .Where(e => eventIds.Contains(e.Id)) .ToDictionaryAsync(e => e.Id, cancellationToken); var matchesByStudent = parseResult.Matches .Where(m => m.Ranking.Student.Id != 0) .GroupBy(m => m.Ranking.Student.Id) .ToDictionary(g => g.Key, g => g.ToList()); var rankingsSaved = 0; foreach (var student in students) { if (!matchesByStudent.TryGetValue(student.Id, out var matches)) continue; student.EventRankings.Clear(); foreach (var match in matches.OrderBy(m => m.Ranking.Rank)) { if (!events.TryGetValue(match.Ranking.EventDefinition.Id, out var eventDefinition)) { _logger.LogWarning( "Skipping ranking for student {StudentId}: event {EventId} was not found", student.Id, match.Ranking.EventDefinition.Id); continue; } student.EventRankings.Add(new StudentEventRanking { Student = student, EventDefinition = eventDefinition, Rank = match.Ranking.Rank }); rankingsSaved++; } } await _context.SaveChangesAsync(cancellationToken); return new StudentEventRankingSaveResult { StudentsUpdated = students.Count, RankingsSaved = rankingsSaved }; } private static List GetStudentIds(StudentEventRankingParseResult parseResult) => [.. parseResult.Matches .Select(m => m.Ranking.Student.Id) .Where(id => id != 0) .Distinct()]; }