using BlueLaminate.Core.Skins;
using BlueLaminate.Scraper.Skins;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System.CommandLine;
namespace BlueLaminate.Cli.Commands;
///
/// sync-skins: load the CS2 skin catalogue and upsert it (throttled monthly).
/// Presentation over ; --dry-run
/// loads and prints via without touching the DB.
///
internal static class SyncSkinsCommand
{
public static Command Build(IHost host)
{
var forceOption = new Option("--force")
{
Description = "Ignore the once-a-month throttle and sync now."
};
var dryRunOption = new Option("--dry-run")
{
Description = "Load and print the skins without writing to the database."
};
var command = new Command(
"sync-skins",
"Load the CS2 skin catalogue from the CSGO-API dataset and upsert it (throttled to once a month).")
{
forceOption,
dryRunOption,
};
command.SetAction((parseResult, ct) => RunAsync(
host,
parseResult.GetValue(forceOption),
parseResult.GetValue(dryRunOption),
ct));
return command;
}
private static async Task RunAsync(IHost host, bool force, bool dryRun, CancellationToken ct)
{
using var scope = host.Services.CreateScope();
if (dryRun)
{
return await DryRunAsync(scope.ServiceProvider, ct);
}
var service = scope.ServiceProvider.GetRequiredService();
var result = await service.SyncAsync(force, ct);
if (result.Skipped)
{
Console.WriteLine(
$"Skipped: skins were last synced {result.LastRanAt:u}. "
+ "Next run allowed one month later — pass --force to override.");
}
else
{
Console.WriteLine(
$"Synced {result.Loaded} skins: {result.Inserted} inserted, "
+ $"{result.Updated} updated, "
+ $"{result.Loaded - result.Inserted - result.Updated} unchanged "
+ $"({result.WeaponsCreated} weapons, {result.CollectionsCreated} collections created).");
}
return 0;
}
// Loads the catalogue and prints it without a database — no service involved.
private static async Task DryRunAsync(IServiceProvider sp, CancellationToken ct)
{
var logger = sp.GetRequiredService().CreateLogger("BlueLaminate.Cli.SyncSkins");
var client = sp.GetRequiredService();
logger.LogInformation("Loading skin catalogue (dry run — nothing will be written).");
var skins = await client.FetchAsync(ct);
logger.LogInformation("Loaded {Count} skins.", skins.Count);
Console.WriteLine($"Loaded {skins.Count} skins (dry run, nothing written):");
foreach (var s in skins)
{
var tags = (s.StatTrakAvailable ? " ST" : "") + (s.SouvenirAvailable ? " SV" : "");
var range = s.FloatMin is not null ? $"{s.FloatMin:0.00}-{s.FloatMax:0.00}" : "—";
var sources = s.Sources.Count > 0 ? string.Join(", ", s.Sources.Select(x => x.Name)) : "—";
var idx = $"{s.DefIndex?.ToString() ?? "—"}/{s.PaintIndex?.ToString() ?? "—"}";
Console.WriteLine(
$" {idx,-10} {s.WeaponName,-16} {s.Name,-24} {s.Rarity,-14} {range,-10} {sources}{tags}");
}
return 0;
}
}