using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using SatelliteProvider.Common.Configs; using SatelliteProvider.DataAccess.Models; namespace SatelliteProvider.Services.RouteManagement; // AZ-364 / C11: extracted from RouteProcessingService.CleanupRegionFilesAsync. // Deletes per-region files (CSV, summary, stitched image) once a route has // successfully consumed them. Each delete is best-effort: a failed delete is // logged at warning level and does not abort the cleanup of the remaining // files. Stitched image path is reconstructed from regionId + ReadyDirectory // because regions historically did not always persist that path on the entity. public class RegionFileCleaner { private readonly StorageConfig _storageConfig; private readonly ILogger _logger; public RegionFileCleaner(IOptions storageConfig, ILogger logger) { ArgumentNullException.ThrowIfNull(storageConfig); _storageConfig = storageConfig.Value; _logger = logger; } public Task CleanupAsync(IEnumerable regions, CancellationToken cancellationToken = default) { ArgumentNullException.ThrowIfNull(regions); foreach (var region in regions) { if (cancellationToken.IsCancellationRequested) break; if (region == null) continue; DeleteIfPresent(region.CsvFilePath, "region CSV file"); DeleteIfPresent(region.SummaryFilePath, "region summary file"); var stitchedImagePath = Path.Combine(_storageConfig.ReadyDirectory, $"region_{region.Id}_stitched.jpg"); if (File.Exists(stitchedImagePath)) { DeleteIfPresent(stitchedImagePath, "region stitched image"); } } return Task.CompletedTask; } private void DeleteIfPresent(string? path, string label) { if (string.IsNullOrEmpty(path) || !File.Exists(path)) { return; } try { File.Delete(path); } catch (Exception ex) { _logger.LogWarning(ex, "Failed to delete {Label}: {FilePath}", label, path); } } }