namespace SatelliteProvider.Common.Utils; // AZ-368 / C15: shared CSV writer for tile rows. // Both region and route pipelines previously emitted the same CSV (header // "latitude,longitude,file_path", same OrderByDescending(Latitude).ThenBy(Longitude) // ordering, same F6 numeric format). Two near-identical writers are now one. // // The class is instance-based (no static, per coderule.mdc — file I/O has side // effects). It carries no dependencies, so callers can `new TileCsvWriter()` // at use sites without DI bloat. public sealed class TileCsvWriter { public const string Header = "latitude,longitude,file_path"; public async Task WriteAsync(string filePath, IEnumerable rows, CancellationToken cancellationToken = default) { ArgumentNullException.ThrowIfNull(filePath); ArgumentNullException.ThrowIfNull(rows); var ordered = rows.OrderByDescending(r => r.Latitude).ThenBy(r => r.Longitude).ToList(); await using var writer = new StreamWriter(filePath); await writer.WriteLineAsync(Header.AsMemory(), cancellationToken); foreach (var row in ordered) { cancellationToken.ThrowIfCancellationRequested(); var line = $"{row.Latitude:F6},{row.Longitude:F6},{row.FilePath}"; await writer.WriteLineAsync(line.AsMemory(), cancellationToken); } } } public sealed record TileCsvRow(double Latitude, double Longitude, string FilePath);