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();
}
}