Files
hackathon-acapulquitos-boys…/lib/features/routes/data/repositories/routes_repository.dart

112 lines
3.4 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// lib/features/routes/data/repositories/routes_repository.dart
import '../datasources/routes_local_datasource.dart';
import '../../domain/entities/route_entities.dart';
import '../../domain/entities/haversine.dart';
class RoutesRepository {
final RoutesLocalDatasource _datasource;
RoutesRepository({RoutesLocalDatasource? datasource})
: _datasource = datasource ?? RoutesLocalDatasource();
/// Obtiene todas las rutas disponibles
Future<List<TruckRoute>> obtenerRutas() => _datasource.cargarRutas();
/// Obtiene una ruta por su ID
Future<TruckRoute?> obtenerRutaPorId(String routeId) async {
final rutas = await obtenerRutas();
try {
return rutas.firstWhere((r) => r.routeId == routeId);
} catch (_) {
return null;
}
}
/// Asigna la ruta más cercana a un domicilio usando Haversine.
/// Cero Google Maps — motor espacial propio.
Future<RouteAssignmentResult> asignarRuta(
double userLat,
double userLng,
) async {
final centroides = await _datasource.generarCentroides();
return Haversine.findNearestRoute(userLat, userLng, centroides);
}
/// Calcula ETA en minutos desde la posición actual del camión
/// hasta el punto más cercano al domicilio del usuario.
Future<ETAResult> calcularETA(
String routeId,
double userLat,
double userLng,
) async {
final ruta = await obtenerRutaPorId(routeId);
if (ruta == null) throw Exception('Ruta $routeId no encontrada');
// Encontrar posición más cercana al usuario en la ruta
double minDist = double.infinity;
int nearestIndex = 0;
for (int i = 0; i < ruta.positions.length - 1; i++) {
final pos = ruta.positions[i];
final d = Haversine.distanceKm(userLat, userLng, pos.lat, pos.lng);
if (d < minDist) {
minDist = d;
nearestIndex = i;
}
}
final posicionCercana = ruta.positions[nearestIndex];
final ahora = DateTime.now();
// Simular cuándo llegará el camión a esa posición
final horaLlegada = posicionCercana.timestamp;
final etaMinutos = horaLlegada.difference(ahora).inMinutes;
return ETAResult(
routeId: routeId,
routeName: ruta.name,
etaMinutos: etaMinutos.clamp(0, 999),
distanciaKm: minDist,
posicionActual: posicionCercana,
ventanaInicio: _formatHora(horaLlegada),
ventanaFin: _formatHora(horaLlegada.add(const Duration(minutes: 15))),
);
}
String _formatHora(DateTime dt) {
final hora = dt.hour > 12 ? dt.hour - 12 : dt.hour;
final minutos = dt.minute.toString().padLeft(2, '0');
final periodo = dt.hour >= 12 ? 'pm' : 'am';
return '$hora:$minutos $periodo';
}
}
class ETAResult {
final String routeId;
final String routeName;
final int etaMinutos;
final double distanciaKm;
final RoutePosition posicionActual;
final String ventanaInicio;
final String ventanaFin;
const ETAResult({
required this.routeId,
required this.routeName,
required this.etaMinutos,
required this.distanciaKm,
required this.posicionActual,
required this.ventanaInicio,
required this.ventanaFin,
});
String get ventana => '$ventanaInicio $ventanaFin';
String get mensaje {
if (etaMinutos <= 0) return 'El camión está pasando ahora. ¡Saca tu basura!';
if (etaMinutos <= 10) return 'El camión llega en ~$etaMinutos min. ¡Saca tu basura!';
return 'El camión llega entre $ventana.';
}
}