using Microsoft.EntityFrameworkCore; using DramaLing.Api.Data; using DramaLing.Api.Models.Entities; namespace DramaLing.Api.Repositories; /// /// 簡化的 Flashcard Repository 實作 /// public class SimpleFlashcardRepository : BaseRepository, IFlashcardRepository { public SimpleFlashcardRepository(DramaLingDbContext context, ILogger logger) : base(context, logger) { } public async Task> GetFlashcardsByUserIdAsync(Guid userId) { return await _dbSet.AsNoTracking().Where(f => f.UserId == userId).ToListAsync(); } public async Task> GetFlashcardsByCardSetIdAsync(Guid cardSetId) { return await _dbSet.AsNoTracking().Where(f => f.CardSetId == cardSetId).ToListAsync(); } public async Task> GetDueFlashcardsAsync(Guid userId, DateTime dueDate) { return await _dbSet.AsNoTracking() .Where(f => f.UserId == userId && f.NextReviewDate <= dueDate) .ToListAsync(); } public async Task> GetFlashcardsByDifficultyAsync(Guid userId, string difficultyLevel) { return await _dbSet.AsNoTracking() .Where(f => f.UserId == userId && f.DifficultyLevel == difficultyLevel) .ToListAsync(); } public async Task> GetRecentlyAddedAsync(Guid userId, int count) { return await _dbSet.AsNoTracking() .Where(f => f.UserId == userId) .OrderByDescending(f => f.CreatedAt) .Take(count) .ToListAsync(); } public async Task> GetMostReviewedAsync(Guid userId, int count) { return await _dbSet.AsNoTracking() .Where(f => f.UserId == userId) .OrderByDescending(f => f.TimesReviewed) .Take(count) .ToListAsync(); } public async Task GetTotalFlashcardsCountAsync(Guid userId) { return await _dbSet.CountAsync(f => f.UserId == userId && !f.IsArchived); } public async Task GetMasteredFlashcardsCountAsync(Guid userId) { return await _dbSet.CountAsync(f => f.UserId == userId && f.MasteryLevel >= 5); } public async Task> GetFlashcardsByDifficultyStatsAsync(Guid userId) { var stats = await _dbSet .Where(f => f.UserId == userId && !f.IsArchived) .GroupBy(f => f.DifficultyLevel) .Select(g => new { Level = g.Key, Count = g.Count() }) .ToDictionaryAsync(x => x.Level ?? "Unknown", x => x.Count); return stats; } public async Task> SearchFlashcardsAsync(Guid userId, string searchTerm) { var term = searchTerm.ToLower(); return await _dbSet.AsNoTracking() .Where(f => f.UserId == userId && (f.Word.ToLower().Contains(term) || f.Translation.ToLower().Contains(term))) .ToListAsync(); } public async Task> GetFavoriteFlashcardsAsync(Guid userId) { return await _dbSet.AsNoTracking() .Where(f => f.UserId == userId && f.IsFavorite) .ToListAsync(); } public async Task> GetArchivedFlashcardsAsync(Guid userId) { return await _dbSet.AsNoTracking() .Where(f => f.UserId == userId && f.IsArchived) .ToListAsync(); } public async Task BulkUpdateMasteryLevelAsync(IEnumerable flashcardIds, int newMasteryLevel) { try { var ids = flashcardIds.ToList(); var flashcards = await _dbSet.Where(f => ids.Contains(f.Id)).ToListAsync(); foreach (var flashcard in flashcards) { flashcard.MasteryLevel = newMasteryLevel; flashcard.UpdatedAt = DateTime.UtcNow; } return true; } catch { return false; } } public async Task BulkUpdateNextReviewDateAsync(IEnumerable flashcardIds, DateTime newDate) { try { var ids = flashcardIds.ToList(); var flashcards = await _dbSet.Where(f => ids.Contains(f.Id)).ToListAsync(); foreach (var flashcard in flashcards) { flashcard.NextReviewDate = newDate; flashcard.UpdatedAt = DateTime.UtcNow; } return true; } catch { return false; } } public async Task> GetFlashcardsWithIncludesAsync(Guid userId, bool includeTags = false, bool includeStudyRecords = false) { var query = _dbSet.AsNoTracking().Where(f => f.UserId == userId); if (includeTags) { query = query.Include(f => f.FlashcardTags!); } return await query.ToListAsync(); } }