< Summary

Information
Class: Orchestrator.Commands.Observability.AnalyzeMatch.AnalyzeMatchContextDocumentInfo
Assembly: Orchestrator
File(s): /home/runner/work/KicktippAi/KicktippAi/src/Orchestrator/Commands/Observability/AnalyzeMatch/AnalyzeMatchCommandHelpers.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 1
Coverable lines: 1
Total lines: 199
Line coverage: 0%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%210%
get_Document()100%210%
set_Document(...)100%210%
get_Version()100%210%
set_Version(...)100%210%
.ctor(...)100%210%

File(s)

/home/runner/work/KicktippAi/KicktippAi/src/Orchestrator/Commands/Observability/AnalyzeMatch/AnalyzeMatchCommandHelpers.cs

#LineLine coverage
 1using System.Text;
 2using EHonda.KicktippAi.Core;
 3using Microsoft.Extensions.Logging;
 4using Spectre.Console;
 5using FirebaseAdapter;
 6using KicktippIntegration;
 7
 8namespace Orchestrator.Commands.Observability.AnalyzeMatch;
 9
 010internal sealed record AnalyzeMatchContextDocumentInfo(DocumentContext Document, int Version);
 11
 12internal static class AnalyzeMatchCommandHelpers
 13{
 14    public static ILoggerFactory CreateLoggerFactory(bool debug)
 15    {
 16        return LoggerFactory.Create(builder =>
 17        {
 18            builder.AddSimpleConsole(options =>
 19            {
 20                options.SingleLine = true;
 21                options.IncludeScopes = false;
 22                options.ColorBehavior = Microsoft.Extensions.Logging.Console.LoggerColorBehavior.Enabled;
 23            });
 24            builder.SetMinimumLevel(debug ? LogLevel.Information : LogLevel.Error);
 25        });
 26    }
 27
 28    public static async Task<Match?> ResolveMatchAsync(
 29        AnalyzeMatchBaseSettings settings,
 30        IKicktippClient? kicktippClient,
 31        ILogger logger,
 32        string communityContext)
 33    {
 34
 35        if (kicktippClient != null)
 36        {
 37            try
 38            {
 39                var matches = await kicktippClient.GetMatchesWithHistoryAsync(communityContext);
 40                var found = matches.FirstOrDefault(m =>
 41                    m.Match.Matchday == settings.Matchday &&
 42                    string.Equals(m.Match.HomeTeam, settings.HomeTeam, StringComparison.OrdinalIgnoreCase) &&
 43                    string.Equals(m.Match.AwayTeam, settings.AwayTeam, StringComparison.OrdinalIgnoreCase));
 44
 45                if (found != null)
 46                {
 47                    AnsiConsole.MarkupLine("[dim]Using match metadata from Kicktipp schedule[/]");
 48                    return found.Match;
 49                }
 50
 51                logger.LogWarning(
 52                    "Match not found via Kicktipp lookup for community {CommunityContext}, matchday {Matchday}, teams {H
 53                    communityContext,
 54                    settings.Matchday,
 55                    settings.HomeTeam,
 56                    settings.AwayTeam);
 57            }
 58            catch (Exception ex)
 59            {
 60                logger.LogWarning(ex, "Failed to fetch match metadata from Kicktipp; continuing with provided details");
 61            }
 62        }
 63        else
 64        {
 65            logger.LogWarning("Kicktipp client not configured; continuing with provided match details");
 66        }
 67
 68        return new Match(
 69            settings.HomeTeam,
 70            settings.AwayTeam,
 71            default,
 72            settings.Matchday!.Value);
 73    }
 74
 75    public static async Task<List<AnalyzeMatchContextDocumentInfo>> GetMatchContextDocumentsAsync(
 76        IContextRepository contextRepository,
 77        string homeTeam,
 78        string awayTeam,
 79        string communityContext,
 80        bool verbose)
 81    {
 82        var contextDocuments = new List<AnalyzeMatchContextDocumentInfo>();
 83        var homeAbbreviation = GetTeamAbbreviation(homeTeam);
 84        var awayAbbreviation = GetTeamAbbreviation(awayTeam);
 85
 86        var requiredDocuments = new[]
 87        {
 88            "bundesliga-standings.csv",
 89            $"community-rules-{communityContext}.md",
 90            $"recent-history-{homeAbbreviation}.csv",
 91            $"recent-history-{awayAbbreviation}.csv",
 92            $"home-history-{homeAbbreviation}.csv",
 93            $"away-history-{awayAbbreviation}.csv",
 94            $"head-to-head-{homeAbbreviation}-vs-{awayAbbreviation}.csv"
 95        };
 96
 97        var optionalDocuments = new[]
 98        {
 99            $"{homeAbbreviation}-transfers.csv",
 100            $"{awayAbbreviation}-transfers.csv"
 101        };
 102
 103        if (verbose)
 104        {
 105            AnsiConsole.MarkupLine($"[dim]Looking for {requiredDocuments.Length} required context documents in database[
 106        }
 107
 108        foreach (var documentName in requiredDocuments)
 109        {
 110            var contextDoc = await contextRepository.GetLatestContextDocumentAsync(documentName, communityContext);
 111            if (contextDoc != null)
 112            {
 113                contextDocuments.Add(new AnalyzeMatchContextDocumentInfo(new DocumentContext(contextDoc.DocumentName, co
 114
 115                if (verbose)
 116                {
 117                    AnsiConsole.MarkupLine($"[dim]  ✓ Retrieved {documentName} (version {contextDoc.Version})[/]");
 118                }
 119            }
 120            else if (verbose)
 121            {
 122                AnsiConsole.MarkupLine($"[dim]  ✗ Missing {documentName}[/]");
 123            }
 124        }
 125
 126        foreach (var documentName in optionalDocuments)
 127        {
 128            try
 129            {
 130                var contextDoc = await contextRepository.GetLatestContextDocumentAsync(documentName, communityContext);
 131                if (contextDoc != null)
 132                {
 133                    contextDocuments.Add(new AnalyzeMatchContextDocumentInfo(new DocumentContext(contextDoc.DocumentName
 134
 135                    if (verbose)
 136                    {
 137                        AnsiConsole.MarkupLine($"[dim]  ✓ Retrieved optional {documentName} (version {contextDoc.Version
 138                    }
 139                }
 140                else if (verbose)
 141                {
 142                    AnsiConsole.MarkupLine($"[dim]  · Missing optional {documentName}[/]");
 143                }
 144            }
 145            catch (Exception ex)
 146            {
 147                if (verbose)
 148                {
 149                    AnsiConsole.MarkupLine($"[dim]  · Failed optional {documentName}: {Markup.Escape(ex.Message)}[/]");
 150                }
 151            }
 152        }
 153
 154        return contextDocuments;
 155    }
 156
 157    private static string GetTeamAbbreviation(string teamName)
 158    {
 159        var abbreviations = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
 160        {
 161            { "1. FC Heidenheim 1846", "fch" },
 162            { "1. FC Köln", "fck" },
 163            { "1. FC Union Berlin", "fcu" },
 164            { "1899 Hoffenheim", "tsg" },
 165            { "Bayer 04 Leverkusen", "b04" },
 166            { "Bor. Mönchengladbach", "bmg" },
 167            { "Borussia Dortmund", "bvb" },
 168            { "Eintracht Frankfurt", "sge" },
 169            { "FC Augsburg", "fca" },
 170            { "FC Bayern München", "fcb" },
 171            { "FC St. Pauli", "fcs" },
 172            { "FSV Mainz 05", "m05" },
 173            { "Hamburger SV", "hsv" },
 174            { "RB Leipzig", "rbl" },
 175            { "SC Freiburg", "scf" },
 176            { "VfB Stuttgart", "vfb" },
 177            { "VfL Wolfsburg", "wob" },
 178            { "Werder Bremen", "svw" }
 179        };
 180
 181        if (abbreviations.TryGetValue(teamName, out var abbreviation))
 182        {
 183            return abbreviation;
 184        }
 185
 186        var words = teamName.Split(' ', StringSplitOptions.RemoveEmptyEntries);
 187        var builder = new StringBuilder();
 188
 189        foreach (var word in words.Take(3))
 190        {
 191            if (word.Length > 0 && char.IsLetter(word[0]))
 192            {
 193                builder.Append(char.ToLowerInvariant(word[0]));
 194            }
 195        }
 196
 197        return builder.Length > 0 ? builder.ToString() : "unknown";
 198    }
 199}