aboutsummaryrefslogtreecommitdiff
path: root/src/Enmarcha.Backend/Services/Processors/TussaRealTimeProcessor.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Enmarcha.Backend/Services/Processors/TussaRealTimeProcessor.cs')
-rw-r--r--src/Enmarcha.Backend/Services/Processors/TussaRealTimeProcessor.cs94
1 files changed, 94 insertions, 0 deletions
diff --git a/src/Enmarcha.Backend/Services/Processors/TussaRealTimeProcessor.cs b/src/Enmarcha.Backend/Services/Processors/TussaRealTimeProcessor.cs
new file mode 100644
index 0000000..7808a3f
--- /dev/null
+++ b/src/Enmarcha.Backend/Services/Processors/TussaRealTimeProcessor.cs
@@ -0,0 +1,94 @@
+using Enmarcha.Backend.Helpers;
+using Enmarcha.Backend.Types.Arrivals;
+using Enmarcha.Sources.Tussa;
+using Arrival = Enmarcha.Backend.Types.Arrivals.Arrival;
+
+namespace Enmarcha.Backend.Services.Processors;
+
+public class TussaRealTimeProcessor : AbstractRealTimeProcessor
+{
+ private readonly SantiagoRealtimeEstimatesProvider _realtime;
+ private readonly FeedService _feedService;
+ private readonly ILogger<TussaRealTimeProcessor> _logger;
+
+ public TussaRealTimeProcessor(
+ SantiagoRealtimeEstimatesProvider realtime,
+ FeedService feedService,
+ ILogger<TussaRealTimeProcessor> logger)
+ {
+ _realtime = realtime;
+ _feedService = feedService;
+ _logger = logger;
+ }
+
+ public override async Task ProcessAsync(ArrivalsContext context)
+ {
+ if (!context.StopId.StartsWith("tussa:")) return;
+
+ var normalizedCode = _feedService.NormalizeStopCode("tussa", context.StopCode);
+ if (!int.TryParse(normalizedCode, out var numericStopId)) return;
+
+ try
+ {
+ var realtime = await _realtime.GetEstimatesForStop(numericStopId);
+ System.Diagnostics.Activity.Current?.SetTag("realtime.count", realtime.Count);
+
+ var usedTripIds = new HashSet<string>();
+
+ foreach (var estimate in realtime)
+ {
+ var bestMatch = context.Arrivals
+ .Where(a => !usedTripIds.Contains(a.TripId))
+ .Where(a => a.Route.RouteIdInGtfs.Trim() == estimate.Id.ToString())
+ .Select(a => new
+ {
+ Arrival = a,
+ TimeDiff = estimate.MinutesToArrive - a.Estimate.Minutes, // RealTime - Schedule
+ RouteMatch = true
+ })
+ .Where(x => x.RouteMatch) // Strict route matching
+ .Where(x => x.TimeDiff is >= -5 and <= 35) // Allow 2m early (RealTime < Schedule) or 25m late (RealTime > Schedule)
+ .OrderBy(x => Math.Abs(x.TimeDiff)) // Best time fit
+ .FirstOrDefault();
+
+ if (bestMatch is null)
+ {
+ context.Arrivals.Add(new Arrival
+ {
+ TripId = $"tussa:rt:{estimate.Id}:{estimate.MinutesToArrive}",
+ Route = new RouteInfo
+ {
+ GtfsId = $"tussa:{estimate.Id}",
+ ShortName = estimate.Sinoptico,
+ Colour = estimate.Colour,
+ TextColour = ContrastHelper.GetBestTextColour(estimate.Colour)
+ },
+ Headsign = new HeadsignInfo
+ {
+ Badge = "T.REAL",
+ Destination = estimate.Name
+ },
+ Estimate = new ArrivalDetails
+ {
+ Minutes = estimate.MinutesToArrive,
+ Precision = ArrivalPrecision.Confident
+ }
+ });
+ continue;
+ }
+
+ var arrival = bestMatch.Arrival;
+
+ arrival.Estimate.Minutes = estimate.MinutesToArrive;
+ arrival.Estimate.Precision = ArrivalPrecision.Confident;
+
+ usedTripIds.Add(arrival.TripId);
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Error fetching Santiago real-time data for stop {StopId}", context.StopId);
+ }
+ }
+
+}