using Microsoft.Extensions.Configuration; using QuestionsApi.Models; using System.Text.Json; namespace QuestionsApi.Services; public static class DynamicBlueprintCommand { public static async Task RunAsync(string[] args, TextWriter output) { var apply = args.Contains("--apply", StringComparer.OrdinalIgnoreCase); var sourceIndex = Array.FindIndex(args, value => value.Equals("--source", StringComparison.OrdinalIgnoreCase)); var source = sourceIndex >= 0 && sourceIndex + 1 < args.Length ? args[sourceIndex + 1] : Path.Combine(AppContext.BaseDirectory, "content", "dynamic_questions"); if (!Directory.Exists(source)) { await output.WriteLineAsync($"Dynamic blueprint directory not found: {source}"); return 2; } var json = new JsonSerializerOptions(JsonSerializerDefaults.Web) { PropertyNameCaseInsensitive = true }; var blueprints = new List(); foreach (var file in Directory.EnumerateFiles(source, "*.json", SearchOption.AllDirectories)) blueprints.AddRange(JsonSerializer.Deserialize>(await File.ReadAllTextAsync(file), json) ?? []); var generator = new DynamicQuestionGenerator(); var generatedVariants = 0; foreach (var blueprint in blueprints) { var error = DynamicQuestionGenerator.Validate(blueprint); if (error is not null) throw new InvalidDataException($"{blueprint.ExternalId} v{blueprint.Version}: {error}"); var validationSeeds = blueprint.QualityStandardVersion >= 2 ? 10_000 : 1_000; for (var seed = 0; seed < validationSeeds; seed++) generator.Generate(blueprint, seed.ToString(), seed.ToString()); generatedVariants += validationSeeds; } await output.WriteLineAsync($"Validated {blueprints.Count} blueprints across {generatedVariants:N0} generated variants."); if (!apply) { await output.WriteLineAsync("Dry run only. Pass --apply to publish."); return 0; } var configuration = new ConfigurationBuilder() .AddJsonFile("appsettings.json", optional: true) .AddEnvironmentVariables() .Build(); var store = new DynamicQuestionStore(new MongoDatabaseProvider(configuration)); var result = await store.UpsertBlueprintsAsync(blueprints); await output.WriteLineAsync($"Promotion complete: {result.Inserted} inserted, {result.Unchanged} unchanged."); return 0; } }