< Summary

Information
Class: Orchestrator.Commands.Utility.Snapshots.SnapshotsFetchCommand
Assembly: Orchestrator
File(s): /home/runner/work/KicktippAi/KicktippAi/src/Orchestrator/Commands/Utility/Snapshots/SnapshotsFetchCommand.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 163
Coverable lines: 163
Total lines: 218
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 24
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%210%
ExecuteAsync()0%620%
FetchSnapshotsAsync()100%210%
<FetchSnapshotsAsync()0%420200%
SaveSnapshotAsync()100%210%
WarnIfNotGitignored(...)0%620%

File(s)

/home/runner/work/KicktippAi/KicktippAi/src/Orchestrator/Commands/Utility/Snapshots/SnapshotsFetchCommand.cs

#LineLine coverage
 1using Microsoft.Extensions.Logging;
 2using Spectre.Console;
 3using Spectre.Console.Cli;
 4using Orchestrator.Infrastructure.Factories;
 5
 6namespace Orchestrator.Commands.Utility.Snapshots;
 7
 8/// <summary>
 9/// Command for fetching HTML snapshots from Kicktipp.
 10/// </summary>
 11public class SnapshotsFetchCommand : AsyncCommand<SnapshotsFetchSettings>
 12{
 13    private readonly IAnsiConsole _console;
 14    private readonly IKicktippClientFactory _kicktippClientFactory;
 15    private readonly ILogger<SnapshotsFetchCommand> _logger;
 16
 017    public SnapshotsFetchCommand(
 018        IAnsiConsole console,
 019        IKicktippClientFactory kicktippClientFactory,
 020        ILogger<SnapshotsFetchCommand> logger)
 21    {
 022        _console = console;
 023        _kicktippClientFactory = kicktippClientFactory;
 024        _logger = logger;
 025    }
 26
 27    public override async Task<int> ExecuteAsync(CommandContext context, SnapshotsFetchSettings settings)
 28    {
 29
 30        try
 31        {
 32            // Validate settings
 033            if (string.IsNullOrWhiteSpace(settings.Community))
 34            {
 035                _console.MarkupLine("[red]Error: Community is required[/]");
 036                return 1;
 37            }
 38
 039            _console.MarkupLine("[green]Fetching snapshots...[/]");
 040            _console.MarkupLine($"[blue]Community:[/] [yellow]{settings.Community}[/]");
 041            _console.MarkupLine($"[blue]Output directory:[/] [yellow]{settings.OutputDirectory}[/]");
 42
 43            // Create output directory
 044            var outputPath = Path.GetFullPath(settings.OutputDirectory);
 045            Directory.CreateDirectory(outputPath);
 46
 47            // Warn if not gitignored
 048            WarnIfNotGitignored(_console, outputPath);
 49
 50            // Create snapshot client using factory (factory handles env var loading)
 051            var snapshotClient = _kicktippClientFactory.CreateSnapshotClient();
 52
 053            var savedCount = await FetchSnapshotsAsync(_console, snapshotClient, settings.Community, outputPath);
 54
 055            _console.WriteLine();
 056            _console.MarkupLine($"[green]Done![/] Saved {savedCount} snapshot(s) to [yellow]{outputPath}[/]");
 057            _console.WriteLine();
 058            _console.MarkupLine("[dim]Next step: Run 'snapshots encrypt' to encrypt them for committing[/]");
 59
 060            return 0;
 61        }
 062        catch (Exception ex)
 63        {
 064            _logger.LogError(ex, "Error fetching snapshots");
 065            _console.MarkupLine($"[red]Error:[/] {ex.Message}");
 066            return 1;
 67        }
 068    }
 69
 70    internal static async Task<int> FetchSnapshotsAsync(IAnsiConsole console, SnapshotClient snapshotClient, string comm
 71    {
 072        var savedCount = 0;
 73
 074        await console.Status()
 075            .StartAsync("Fetching snapshots...", async ctx =>
 076            {
 077                // 0. Login page (fetched without community context)
 078                ctx.Status("Fetching login page...");
 079                var loginContent = await snapshotClient.FetchLoginPageAsync();
 080                if (loginContent != null)
 081                {
 082                    await SaveSnapshotAsync(outputPath, "login.html", loginContent);
 083                    savedCount++;
 084                    console.MarkupLine("[green]✓[/] Saved login.html");
 085                }
 086                else
 087                {
 088                    console.MarkupLine("[red]✗[/] Failed to fetch login page");
 089                }
 090
 091                // 1. Tabellen (standings)
 092                ctx.Status("Fetching tabellen...");
 093                var tabellenContent = await snapshotClient.FetchStandingsPageAsync(community);
 094                if (tabellenContent != null)
 095                {
 096                    await SaveSnapshotAsync(outputPath, "tabellen.html", tabellenContent);
 097                    savedCount++;
 098                    console.MarkupLine("[green]✓[/] Saved tabellen.html");
 099                }
 0100                else
 0101                {
 0102                    console.MarkupLine("[red]✗[/] Failed to fetch tabellen");
 0103                }
 0104
 0105                // 2. Tippabgabe (main betting page)
 0106                ctx.Status("Fetching tippabgabe...");
 0107                var tippabgabeContent = await snapshotClient.FetchTippabgabePageAsync(community);
 0108                if (tippabgabeContent != null)
 0109                {
 0110                    await SaveSnapshotAsync(outputPath, "tippabgabe.html", tippabgabeContent);
 0111                    savedCount++;
 0112                    console.MarkupLine("[green]✓[/] Saved tippabgabe.html");
 0113                }
 0114                else
 0115                {
 0116                    console.MarkupLine("[red]✗[/] Failed to fetch tippabgabe");
 0117                }
 0118
 0119                // 3. Tippabgabe bonus (bonus questions)
 0120                ctx.Status("Fetching tippabgabe-bonus...");
 0121                var bonusContent = await snapshotClient.FetchBonusPageAsync(community);
 0122                if (bonusContent != null)
 0123                {
 0124                    await SaveSnapshotAsync(outputPath, "tippabgabe-bonus.html", bonusContent);
 0125                    savedCount++;
 0126                    console.MarkupLine("[green]✓[/] Saved tippabgabe-bonus.html");
 0127                }
 0128                else
 0129                {
 0130                    console.MarkupLine("[red]✗[/] Failed to fetch tippabgabe-bonus");
 0131                }
 0132
 0133                // 4. Spielinfo pages (match details with history)
 0134                ctx.Status("Fetching spielinfo pages...");
 0135                var spielinfoPages = await snapshotClient.FetchAllSpielinfoAsync(community);
 0136
 0137                foreach (var (fileName, content) in spielinfoPages)
 0138                {
 0139                    await SaveSnapshotAsync(outputPath, $"{fileName}.html", content);
 0140                    savedCount++;
 0141                }
 0142
 0143                if (spielinfoPages.Count > 0)
 0144                {
 0145                    console.MarkupLine($"[green]✓[/] Saved {spielinfoPages.Count} spielinfo pages");
 0146                }
 0147                else
 0148                {
 0149                    console.MarkupLine("[yellow]![/] No spielinfo pages found");
 0150                }
 0151
 0152                // 5. Spielinfo pages with home/away history (ansicht=2)
 0153                ctx.Status("Fetching spielinfo home/away pages...");
 0154                var homeAwayPages = await snapshotClient.FetchAllSpielinfoHomeAwayAsync(community);
 0155
 0156                foreach (var (fileName, content) in homeAwayPages)
 0157                {
 0158                    await SaveSnapshotAsync(outputPath, $"{fileName}.html", content);
 0159                    savedCount++;
 0160                }
 0161
 0162                if (homeAwayPages.Count > 0)
 0163                {
 0164                    console.MarkupLine($"[green]✓[/] Saved {homeAwayPages.Count} spielinfo home/away pages");
 0165                }
 0166                else
 0167                {
 0168                    console.MarkupLine("[yellow]![/] No spielinfo home/away pages found");
 0169                }
 0170
 0171                // 6. Spielinfo pages with head-to-head history (ansicht=3)
 0172                ctx.Status("Fetching spielinfo head-to-head pages...");
 0173                var h2hPages = await snapshotClient.FetchAllSpielinfoHeadToHeadAsync(community);
 0174
 0175                foreach (var (fileName, content) in h2hPages)
 0176                {
 0177                    await SaveSnapshotAsync(outputPath, $"{fileName}.html", content);
 0178                    savedCount++;
 0179                }
 0180
 0181                if (h2hPages.Count > 0)
 0182                {
 0183                    console.MarkupLine($"[green]✓[/] Saved {h2hPages.Count} spielinfo head-to-head pages");
 0184                }
 0185                else
 0186                {
 0187                    console.MarkupLine("[yellow]![/] No spielinfo head-to-head pages found");
 0188                }
 0189            });
 190
 0191        return savedCount;
 0192    }
 193
 194    internal static async Task SaveSnapshotAsync(string outputPath, string fileName, string content)
 195    {
 0196        var filePath = Path.Combine(outputPath, fileName);
 0197        await File.WriteAllTextAsync(filePath, content);
 0198    }
 199
 200    private static void WarnIfNotGitignored(IAnsiConsole console, string outputPath)
 201    {
 0202        var relativePath = Path.GetRelativePath(Directory.GetCurrentDirectory(), outputPath);
 0203        var directoryName = Path.GetFileName(outputPath.TrimEnd(Path.DirectorySeparatorChar));
 204
 0205        var commonIgnoredPatterns = new[] { "snapshots", "temp", "tmp", "output", "out", ".local" };
 0206        var looksIgnored = commonIgnoredPatterns.Any(p =>
 0207            directoryName.Contains(p, StringComparison.OrdinalIgnoreCase));
 208
 0209        if (!looksIgnored)
 210        {
 0211            console.MarkupLine(
 0212                $"[yellow]⚠ Warning:[/] Output directory '{relativePath}' may not be gitignored.");
 0213            console.MarkupLine(
 0214                "[yellow]  Make sure to add it to .gitignore before committing![/]");
 0215            console.WriteLine();
 216        }
 0217    }
 218}