using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; 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 IStoryProgressRepository. /// This is part of the Infrastructure layer. /// public class StoryProgressRepository : IStoryProgressRepository { private readonly AppDbContext _context; public StoryProgressRepository(AppDbContext context) { _context = context; } public async Task> GetByUserAndLevelAsync( int userId, int levelId, CancellationToken cancellationToken = default) { return await _context.StoryProgress .Where(p => p.UserId == userId && p.LevelId == levelId) .Include(p => p.StorySegment) .OrderBy(p => p.StorySegment != null ? p.StorySegment.Order : 0) .AsNoTracking() .ToListAsync(cancellationToken); } public async Task GetByUserAndSegmentAsync( int userId, int storySegmentId, CancellationToken cancellationToken = default) { return await _context.StoryProgress .FirstOrDefaultAsync( p => p.UserId == userId && p.StorySegmentId == storySegmentId, cancellationToken); } public async Task GetHighestUnlockedOrderAsync( int userId, int levelId, CancellationToken cancellationToken = default) { var highestOrder = await _context.StoryProgress .Where(p => p.UserId == userId && p.LevelId == levelId) .Include(p => p.StorySegment) .Select(p => p.StorySegment != null ? p.StorySegment.Order : 0) .MaxAsync(cancellationToken); return highestOrder == null ? 0 : highestOrder; } public async Task IsSegmentUnlockedAsync( int userId, int storySegmentId, CancellationToken cancellationToken = default) { return await _context.StoryProgress .AnyAsync( p => p.UserId == userId && p.StorySegmentId == storySegmentId, cancellationToken); } public async Task IsSegmentCompletedAsync( int userId, int storySegmentId, CancellationToken cancellationToken = default) { return await _context.StoryProgress .AnyAsync( p => p.UserId == userId && p.StorySegmentId == storySegmentId && p.IsCompleted, cancellationToken); } public async Task AddAsync(StoryProgress progress, CancellationToken cancellationToken = default) { await _context.StoryProgress.AddAsync(progress, cancellationToken); await _context.SaveChangesAsync(cancellationToken); return progress; } public async Task UpdateAsync(StoryProgress progress, CancellationToken cancellationToken = default) { _context.StoryProgress.Update(progress); await _context.SaveChangesAsync(cancellationToken); } public async Task GetTotalSegmentsForLevelAsync(int levelId, CancellationToken cancellationToken = default) { return await _context.StorySegments .CountAsync(s => s.LevelId == levelId && s.IsActive, cancellationToken); } public async Task GetUnlockedCountAsync( int userId, int levelId, CancellationToken cancellationToken = default) { return await _context.StoryProgress .CountAsync( p => p.UserId == userId && p.LevelId == levelId, cancellationToken); } public async Task GetCompletedCountAsync( int userId, int levelId, CancellationToken cancellationToken = default) { return await _context.StoryProgress .CountAsync( p => p.UserId == userId && p.LevelId == levelId && p.IsCompleted, cancellationToken); } }