Skip to main content

Tournament Eligibility Rules Documentation

Overview

Tournament eligibility rules determine who can register for which categories/divisions based on various criteria such as charter captain status, captain's license, pro/amateur status, and past tournament performance.

Common Eligibility Scenarios

Scenario 1: Charter Captains Must Be in Pro Division

var rule = new TournamentEligibilityRule
{
TournamentId = tournamentId,
RuleName = "Charter Captains Must Be Pro",
Description = "All charter captains must register for the Pro division",
RuleType = EligibilityRuleType.CharterCaptain,
RequiresCharterCaptain = true,
Action = EligibilityAction.RequireDivision,
RequiredDivision = "Pro",
IsEnforced = true,
ShowWarning = true
};

Scenario 2: Past Amateur Winners Must Be Pro

var rule = new TournamentEligibilityRule
{
TournamentId = tournamentId,
RuleName = "Past Amateur Winners Must Be Pro",
Description = "Anglers who won the Amateur division last year must register for Pro division this year",
RuleType = EligibilityRuleType.PastDivision,
RequiresPastTournamentWin = true,
PastDivisionRequirement = "Amateur",
YearsSinceWin = 1, // Won amateur last year
Action = EligibilityAction.RequireDivision,
RequiredDivision = "Pro",
IsEnforced = true
};

Scenario 3: Licensed Captains Must Be Pro

var rule = new TournamentEligibilityRule
{
TournamentId = tournamentId,
RuleName = "Licensed Captains Must Be Pro",
Description = "Users with valid captain's licenses must register for Pro division",
RuleType = EligibilityRuleType.CaptainLicense,
RequiresValidCaptainLicense = true,
Action = EligibilityAction.RequireDivision,
RequiredDivision = "Pro",
IsEnforced = true
};

Checking Eligibility During Registration

public async Task<bool> CheckEligibility(Guid userId, int tournamentId, int? categoryId, string? division)
{
var user = await context.Users
.Include(u => u.CaptainLicenses)
.Include(u => u.CharterCaptain)
.FirstOrDefaultAsync(u => u.Id == userId);

var tournament = await context.Tournaments
.Include(t => t.EligibilityRules.Where(er => er.IsActive && er.IsEnforced))
.FirstOrDefaultAsync(t => t.Id == tournamentId);

// Check if user is charter captain
var isCharterCaptain = user.CharterCaptain != null;

// Check if user has valid captain's license
var hasValidLicense = user.CaptainLicenses
.Any(cl => cl.IsActive && cl.Status == LicenseStatus.Active && cl.ExpirationDate > DateTime.UtcNow);

// Check past tournament wins
var pastWins = await context.TournamentResults
.Include(tr => tr.Registration)
.Where(tr => tr.Registration.UserId == userId && tr.Rank == 1)
.ToListAsync();

var isPastWinner = pastWins.Any();
var pastDivision = pastWins.FirstOrDefault()?.Registration.Division;

// Check each eligibility rule
foreach (var rule in tournament.EligibilityRules)
{
bool ruleApplies = false;

// Check charter captain requirement
if (rule.RequiresCharterCaptain && isCharterCaptain)
ruleApplies = true;

// Check captain license requirement
if (rule.RequiresValidCaptainLicense && hasValidLicense)
ruleApplies = true;

// Check past winner requirement
if (rule.RequiresPastTournamentWin && isPastWinner)
{
// Check if it's within the time window
if (!rule.YearsSinceWin.HasValue ||
pastWins.Any(pw => (DateTime.UtcNow - pw.CaughtAt).TotalDays <= rule.YearsSinceWin.Value * 365))
{
// Check division requirement
if (string.IsNullOrEmpty(rule.PastDivisionRequirement) ||
pastDivision == rule.PastDivisionRequirement)
{
ruleApplies = true;
}
}
}

if (ruleApplies)
{
// Apply rule action
switch (rule.Action)
{
case EligibilityAction.RequireDivision:
if (division != rule.RequiredDivision)
return false; // Must register for required division
break;

case EligibilityAction.RequireCategory:
if (categoryId != rule.RequiredCategoryId)
return false; // Must register for required category
break;

case EligibilityAction.PreventRegistration:
return false; // Cannot register

case EligibilityAction.ShowWarning:
// Show warning but allow registration
break;
}
}
}

return true; // Eligible
}

Auto-Assigning Division Based on Eligibility

public async Task<string?> DetermineRequiredDivision(Guid userId, int tournamentId)
{
var user = await context.Users
.Include(u => u.CaptainLicenses)
.Include(u => u.CharterCaptain)
.FirstOrDefaultAsync(u => u.Id == userId);

var tournament = await context.Tournaments
.Include(t => t.EligibilityRules.Where(er => er.IsActive && er.IsEnforced))
.FirstOrDefaultAsync(t => t.Id == tournamentId);

// Check eligibility rules
foreach (var rule in tournament.EligibilityRules.OrderBy(er => er.DisplayOrder))
{
if (rule.Action == EligibilityAction.AutoAssignDivision ||
rule.Action == EligibilityAction.RequireDivision)
{
bool ruleApplies = false;

if (rule.RequiresCharterCaptain && user.CharterCaptain != null)
ruleApplies = true;

if (rule.RequiresValidCaptainLicense &&
user.CaptainLicenses.Any(cl => cl.IsActive && cl.Status == LicenseStatus.Active))
ruleApplies = true;

if (ruleApplies && !string.IsNullOrEmpty(rule.RequiredDivision))
{
return rule.RequiredDivision;
}
}
}

return null; // No specific division required
}