using GermanApp.Domain.Entities; using GermanApp.Domain.Interfaces; using GermanApp.Infrastructure.Data.DbContext; using Microsoft.EntityFrameworkCore; namespace GermanApp.Infrastructure.Data.Repositories; /// /// Entity Framework Core implementation of IUserProgressRepository. /// This is part of the Infrastructure layer. /// public class UserProgressRepository : IUserProgressRepository { private readonly AppDbContext _context; public UserProgressRepository(AppDbContext context) { _context = context; } public async Task GetByIdAsync(int id, CancellationToken cancellationToken = default) { return await _context.UserProgress .Include(up => up.User) .Include(up => up.Lesson) .FirstOrDefaultAsync(up => up.Id == id, cancellationToken); } public async Task> GetAllAsync(CancellationToken cancellationToken = default) { return await _context.UserProgress .Include(up => up.User) .Include(up => up.Lesson) .AsNoTracking() .ToListAsync(cancellationToken); } public async Task AddAsync(UserProgress entity, CancellationToken cancellationToken = default) { await _context.UserProgress.AddAsync(entity, cancellationToken); await _context.SaveChangesAsync(cancellationToken); return entity; } public async Task UpdateAsync(UserProgress entity, CancellationToken cancellationToken = default) { _context.UserProgress.Update(entity); await _context.SaveChangesAsync(cancellationToken); } public async Task DeleteAsync(UserProgress entity, CancellationToken cancellationToken = default) { _context.UserProgress.Remove(entity); await _context.SaveChangesAsync(cancellationToken); } public async Task ExistsAsync(int id, CancellationToken cancellationToken = default) { return await _context.UserProgress .AnyAsync(up => up.Id == id, cancellationToken); } public async Task GetByUserAndLessonAsync(int userId, int lessonId, CancellationToken cancellationToken = default) { return await _context.UserProgress .Include(up => up.User) .Include(up => up.Lesson) .FirstOrDefaultAsync(up => up.UserId == userId && up.LessonId == lessonId, cancellationToken); } public async Task> GetByUserAsync(int userId, CancellationToken cancellationToken = default) { return await _context.UserProgress .Include(up => up.Lesson) .ThenInclude(l => l.Level) .Where(up => up.UserId == userId) .OrderBy(up => up.Lesson.Level!.Order) .ThenBy(up => up.Lesson.Order) .AsNoTracking() .ToListAsync(cancellationToken); } public async Task> GetByUserAndLevelAsync(int userId, int levelId, CancellationToken cancellationToken = default) { return await _context.UserProgress .Include(up => up.Lesson) .Where(up => up.UserId == userId && up.Lesson.LevelId == levelId) .OrderBy(up => up.Lesson.Order) .AsNoTracking() .ToListAsync(cancellationToken); } public async Task HasUserCompletedLessonAsync(int userId, int lessonId, CancellationToken cancellationToken = default) { return await _context.UserProgress .AnyAsync(up => up.UserId == userId && up.LessonId == lessonId && up.IsCompleted, cancellationToken); } public async Task GetAverageScoreForLevelAsync(int userId, int levelId, CancellationToken cancellationToken = default) { var progresses = await _context.UserProgress .Where(up => up.UserId == userId && up.Lesson.LevelId == levelId && up.QuizScore > 0) .Select(up => up.QuizScore) .ToListAsync(cancellationToken); if (progresses.Count == 0) return 0; return progresses.Average(); } public async Task GetLevelCompletionPercentageAsync(int userId, int levelId, CancellationToken cancellationToken = default) { // Get total lessons in the level var totalLessons = await _context.Lessons .CountAsync(l => l.LevelId == levelId, cancellationToken); if (totalLessons == 0) return 0; // Get completed lessons count for user in this level var completedCount = await _context.UserProgress .CountAsync(up => up.UserId == userId && up.Lesson.LevelId == levelId && up.IsCompleted, cancellationToken); return (double)completedCount / totalLessons * 100; } }