namespace GermanApp.Domain.Entities;
///
/// Represents a quiz that can be associated with a lesson.
/// A quiz contains multiple questions and has a passing score threshold.
///
public class Quiz
{
public int Id { get; private set; }
public int LessonId { get; private set; }
public string Title { get; private set; } = string.Empty;
public string? Description { get; private set; }
public int PassingScore { get; private set; } = 80; // Default 80%
public int TimeLimitMinutes { get; private set; } = 0; // 0 = no limit
public bool IsActive { get; private set; } = true;
public bool ShuffleQuestions { get; private set; } = true;
public DateTime CreatedAt { get; private set; }
public DateTime? UpdatedAt { get; private set; }
// Navigation property
public virtual Lesson? Lesson { get; private set; }
public virtual ICollection Questions { get; private set; } = new List();
///
/// Constructor for EF Core deserialization.
///
private Quiz() { }
///
/// Factory method to create a new quiz.
///
/// ID of the associated lesson
/// Title of the quiz
/// Optional description
/// Passing score percentage (default 80)
/// Time limit in minutes (0 for no limit)
public static Quiz Create(
int lessonId,
string title,
string? description = null,
int passingScore = 80,
int timeLimitMinutes = 0)
{
if (string.IsNullOrWhiteSpace(title))
throw new ArgumentException("Quiz title cannot be empty", nameof(title));
if (passingScore < 0 || passingScore > 100)
throw new ArgumentOutOfRangeException(nameof(passingScore), "Passing score must be between 0 and 100");
if (timeLimitMinutes < 0)
throw new ArgumentOutOfRangeException(nameof(timeLimitMinutes), "Time limit cannot be negative");
return new Quiz
{
LessonId = lessonId,
Title = title,
Description = description,
PassingScore = passingScore,
TimeLimitMinutes = timeLimitMinutes,
CreatedAt = DateTime.UtcNow
};
}
///
/// Updates the quiz title.
///
public void UpdateTitle(string newTitle)
{
if (string.IsNullOrWhiteSpace(newTitle))
throw new ArgumentException("Quiz title cannot be empty", nameof(newTitle));
Title = newTitle;
UpdatedAt = DateTime.UtcNow;
}
///
/// Updates the quiz description.
///
public void UpdateDescription(string? newDescription)
{
Description = newDescription;
UpdatedAt = DateTime.UtcNow;
}
///
/// Updates the passing score.
///
public void UpdatePassingScore(int newPassingScore)
{
if (newPassingScore < 0 || newPassingScore > 100)
throw new ArgumentOutOfRangeException(nameof(newPassingScore), "Passing score must be between 0 and 100");
PassingScore = newPassingScore;
UpdatedAt = DateTime.UtcNow;
}
///
/// Updates the time limit.
///
public void UpdateTimeLimit(int newTimeLimitMinutes)
{
if (newTimeLimitMinutes < 0)
throw new ArgumentOutOfRangeException(nameof(newTimeLimitMinutes), "Time limit cannot be negative");
TimeLimitMinutes = newTimeLimitMinutes;
UpdatedAt = DateTime.UtcNow;
}
///
/// Updates the associated lesson.
///
public void UpdateLesson(int newLessonId)
{
LessonId = newLessonId;
UpdatedAt = DateTime.UtcNow;
}
///
/// Updates the shuffle questions setting.
///
public void UpdateShuffleQuestions(bool newShuffleQuestions)
{
ShuffleQuestions = newShuffleQuestions;
UpdatedAt = DateTime.UtcNow;
}
///
/// Activates the quiz.
///
public void Activate()
{
IsActive = true;
UpdatedAt = DateTime.UtcNow;
}
///
/// Deactivates the quiz.
///
public void Deactivate()
{
IsActive = false;
UpdatedAt = DateTime.UtcNow;
}
///
/// Adds a question to this quiz.
///
public void AddQuestion(QuizQuestion question)
{
if (question == null)
throw new ArgumentNullException(nameof(question));
Questions.Add(question);
}
///
/// Removes a question from this quiz.
///
public void RemoveQuestion(QuizQuestion question)
{
if (question == null)
throw new ArgumentNullException(nameof(question));
Questions.Remove(question);
}
///
/// Checks if the quiz is passed based on a score percentage.
///
public bool IsPassed(double scorePercentage) => scorePercentage >= PassingScore;
///
/// Calculates the score percentage based on correct answers.
///
public double CalculateScore(int correctAnswers, int totalQuestions)
{
if (totalQuestions == 0)
return 0;
return (double)correctAnswers / totalQuestions * 100;
}
}