using Core.Entities; using FuzzySharp; namespace Core.Utility; /// /// Utility class for matching team names from clipboard text using fuzzy matching. /// public static class TeamClipboardMatcher { /// /// Matches team names from clipboard text against available teams using fuzzy matching. /// /// The text content from the clipboard. /// The collection of available teams to match against. /// The minimum fuzzy match score threshold (0-100). Default is 85. /// A list of teams that match the clipboard text, ordered by match quality. public static List MatchTeamsFromClipboard( string clipboardText, IEnumerable availableTeams, int matchThreshold = 85) { var matchedTeams = new List(); var teamsList = availableTeams.ToList(); if (string.IsNullOrWhiteSpace(clipboardText) || !teamsList.Any()) { return matchedTeams; } // Split clipboard text by newlines var lines = clipboardText.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries); foreach (var line in lines) { // Extract team name portion (before " - " if present, as clipboard format includes student lists) var teamName = ExtractTeamNameFromLine(line); // Skip empty lines or lines that look like headers/metadata if (ShouldSkipLine(teamName)) { continue; } // Find best match using fuzzy matching var matchedTeam = FindBestMatch(teamName, teamsList, matchThreshold); if (matchedTeam != null && !matchedTeams.Any(t => t.Id == matchedTeam.Id)) { matchedTeams.Add(matchedTeam); } } return matchedTeams; } private static string ExtractTeamNameFromLine(string line) { var dashIndex = line.IndexOf(" - "); if (dashIndex > 0) { return line.Substring(0, dashIndex).Trim(); } return line.Trim(); } private static bool ShouldSkipLine(string teamName) { return string.IsNullOrWhiteSpace(teamName) || teamName.StartsWith("--") || teamName.Equals("Unscheduled", StringComparison.OrdinalIgnoreCase); } private static Team? FindBestMatch(string teamName, List availableTeams, int matchThreshold) { // Normalize both strings to lowercase for case-insensitive comparison var normalizedTeamName = teamName.ToLowerInvariant(); var bestMatch = availableTeams .Select(team => new { Team = team, Score = Fuzz.Ratio(normalizedTeamName, team.ToString().ToLowerInvariant()) }) .Where(x => x.Score >= matchThreshold) .OrderByDescending(x => x.Score) .FirstOrDefault(); return bestMatch?.Team; } }