using Core.Entities;
using Core.Models;
using System.Reflection;
namespace Core.Validation;
///
/// Main service for executing validation rules and generating warnings
///
public class ValidationService
{
private readonly ValidationConfiguration _config;
private readonly List> _studentRules;
private readonly List> _teamRules;
private readonly List> _statisticsRules;
// Lazy static singletons for rule definitions (instantiated once per application lifetime)
private static readonly Lazy>> _studentRuleDefinitions =
new(() => DiscoverRules());
private static readonly Lazy>> _teamRuleDefinitions =
new(() => DiscoverRules());
private static readonly Lazy>> _statisticsRuleDefinitions =
new(() => DiscoverRules());
///
/// Create a new validation service with the specified configuration
///
/// Validation configuration (uses Default if null)
public ValidationService(ValidationConfiguration? config = null)
{
_config = config ?? ValidationConfiguration.Default;
// Use the shared rule definitions (singleton pattern)
_studentRules = _studentRuleDefinitions.Value;
_teamRules = _teamRuleDefinitions.Value;
_statisticsRules = _statisticsRuleDefinitions.Value;
}
///
/// Discover all validation rules for a given entity type using reflection
///
/// The entity type to find rules for
/// List of discovered validation rules
private static List> DiscoverRules()
{
var ruleType = typeof(IValidationRule);
return Assembly.GetExecutingAssembly()
.GetTypes()
.Where(t => t.IsClass && !t.IsAbstract && ruleType.IsAssignableFrom(t))
.Select(t => (IValidationRule)Activator.CreateInstance(t)!)
.ToList();
}
///
/// Validate a student's event rankings
///
/// Student to validate
/// Validation context
/// List of validation warnings
public List ValidateStudentRankings(Student student, ValidationContext context)
{
return _studentRules
.Where(rule => rule.AppliesTo(context))
.Select(rule => rule.Validate(student, _config))
.Where(warning => warning != null)
.Cast()
.ToList();
}
///
/// Validate a team configuration
///
/// Team to validate
/// Validation context (defaults to Team)
/// List of validation warnings
public List ValidateTeam(Team team, ValidationContext context = ValidationContext.Team)
{
return _teamRules
.Where(rule => rule.AppliesTo(context))
.Select(rule => rule.Validate(team, _config))
.Where(warning => warning != null)
.Cast()
.ToList();
}
///
/// Validate student event assignment statistics
///
/// Student statistics to validate
/// Validation context
/// List of validation warnings
public List ValidateStudentStatistics(StudentEventStatistics stats, ValidationContext context)
{
return _statisticsRules
.Where(rule => rule.AppliesTo(context))
.Select(rule => rule.Validate(stats, _config))
.Where(warning => warning != null)
.Cast()
.ToList();
}
///
/// Validate all students in a collection
///
/// Students to validate
/// Validation context
/// Dictionary mapping each student to their warnings
public Dictionary> ValidateStudents(
IEnumerable students,
ValidationContext context)
{
return students.ToDictionary(
student => student,
student => ValidateStudentRankings(student, context)
);
}
///
/// Validate all teams in a collection
///
/// Teams to validate
/// Dictionary mapping each team to their warnings
public Dictionary> ValidateTeams(IEnumerable teams)
{
return teams.ToDictionary(
team => team,
team => ValidateTeam(team)
);
}
}