using RolemasterDb.ImportTool.Parsing; namespace RolemasterDb.ImportTool; public sealed class CriticalImportCommandRunner { private readonly CriticalImportManifestLoader manifestLoader = new(); private readonly ImportArtifactWriter artifactWriter = new(); private readonly PdfXmlExtractor pdfXmlExtractor = new(); private readonly CriticalSourceImageArtifactGenerator sourceImageArtifactGenerator; private readonly StandardCriticalTableParser standardParser = new(); private readonly VariantColumnCriticalTableParser variantColumnParser = new(); private readonly GroupedVariantCriticalTableParser groupedVariantParser = new(); public CriticalImportCommandRunner() { sourceImageArtifactGenerator = new CriticalSourceImageArtifactGenerator(pdfXmlExtractor); } public async Task RunAsync(ResetOptions options) { if (!string.Equals(options.Target, "criticals", StringComparison.OrdinalIgnoreCase)) { Console.Error.WriteLine("Only 'criticals' is supported by phase 1."); return 1; } var loader = new CriticalImportLoader(ResolveDatabasePath(options.DatabasePath)); var removedTableCount = await loader.ResetCriticalsAsync(); Console.WriteLine($"Removed {removedTableCount} critical table records."); return 0; } public async Task RunAsync(ExtractOptions options) { var entry = GetManifestEntry(options.Table); var artifactPaths = CreateArtifactPaths(entry.Slug); await pdfXmlExtractor.ExtractAsync(ResolveRepositoryPath(entry.PdfPath), artifactPaths.XmlPath); Console.WriteLine($"Extracted {entry.Slug} to {artifactPaths.XmlPath}"); return 0; } public async Task RunAsync(LoadOptions options) { var entry = GetManifestEntry(options.Table); var artifactPaths = CreateArtifactPaths(entry.Slug); if (!File.Exists(artifactPaths.XmlPath)) { Console.Error.WriteLine($"Missing XML artifact: {artifactPaths.XmlPath}"); return 1; } var xmlContent = await File.ReadAllTextAsync(artifactPaths.XmlPath); var parseResult = Parse(entry, xmlContent); await sourceImageArtifactGenerator.GenerateAsync( ResolveRepositoryPath(entry.PdfPath), artifactPaths, parseResult, CancellationToken.None); await artifactWriter.WriteAsync(artifactPaths, parseResult, CancellationToken.None); if (!parseResult.ValidationReport.IsValid) { throw new InvalidOperationException( $"Validation failed for '{entry.Slug}'. See {artifactPaths.ValidationReportPath} for details."); } foreach (var warning in parseResult.ValidationReport.Warnings) { Console.WriteLine($"Warning: {warning}"); } var loader = new CriticalImportLoader(ResolveDatabasePath(options.DatabasePath)); var result = await loader.LoadAsync(parseResult.Table); Console.WriteLine( $"Loaded {result.TableSlug}: {result.ColumnCount} columns, {result.RollBandCount} roll bands, {result.ResultCount} results."); return 0; } public async Task RunAsync(ImportOptions options) { var extractExitCode = await RunAsync(new ExtractOptions { DatabasePath = options.DatabasePath, Table = options.Table }); if (extractExitCode != 0) { return extractExitCode; } return await RunAsync(new LoadOptions { DatabasePath = options.DatabasePath, Table = options.Table }); } private CriticalImportManifestEntry GetManifestEntry(string tableSlug) { var manifest = manifestLoader.Load(RepositoryPaths.Discover().ManifestPath); return manifest.Tables .Where(item => item.Enabled) .SingleOrDefault(item => string.Equals(item.Slug, tableSlug.Trim(), StringComparison.OrdinalIgnoreCase)) ?? throw new InvalidOperationException($"No enabled manifest entry was found for '{tableSlug}'."); } private CriticalTableParseResult Parse(CriticalImportManifestEntry entry, string xmlContent) { if (string.Equals(entry.Family, "standard", StringComparison.OrdinalIgnoreCase)) { return standardParser.Parse(entry, xmlContent); } if (string.Equals(entry.Family, "variant_column", StringComparison.OrdinalIgnoreCase)) { return variantColumnParser.Parse(entry, xmlContent); } if (string.Equals(entry.Family, "grouped_variant", StringComparison.OrdinalIgnoreCase)) { return groupedVariantParser.Parse(entry, xmlContent); } throw new InvalidOperationException($"Family '{entry.Family}' is not supported by the importer."); } private static ImportArtifactPaths CreateArtifactPaths(string slug) => ImportArtifactPaths.Create(RepositoryPaths.Discover().ArtifactsRootPath, slug); private static string ResolveDatabasePath(string? databasePath) => Path.GetFullPath(databasePath ?? RepositoryPaths.Discover().DefaultDatabasePath); private static string ResolveRepositoryPath(string path) => Path.GetFullPath(Path.Combine(RepositoryPaths.Discover().RootPath, path)); }