from __future__ import annotations """Application services for combined track operations.""" from sqlalchemy.orm import Session from backend.app.models import CombinedTrackCreate, CombinedTrackModel from backend.app.repositories import CombinedTrackRepository, TrackRepository def create_combined_track( session: Session, start_station_id: str, end_station_id: str ) -> CombinedTrackModel | None: """Create a combined track between two stations using pathfinding. Returns the created combined track, or None if no path exists or a combined track already exists between these stations. """ combined_track_repo = CombinedTrackRepository(session) track_repo = TrackRepository(session) # Check if combined track already exists if combined_track_repo.exists_between_stations(start_station_id, end_station_id): return None # Find path between stations path_tracks = track_repo.find_path_between_stations( start_station_id, end_station_id) if not path_tracks: return None # Combine geometries combined_coords = track_repo.combine_track_geometries(path_tracks) if len(combined_coords) < 2: return None # Calculate total length total_length = sum(track.length_meters or 0 for track in path_tracks) # Get max speed (use the minimum speed of all tracks) max_speeds = [ track.max_speed_kph for track in path_tracks if track.max_speed_kph] max_speed = min(max_speeds) if max_speeds else None # Get constituent track IDs constituent_track_ids = [str(track.id) for track in path_tracks] # Create combined track create_data = CombinedTrackCreate( start_station_id=start_station_id, end_station_id=end_station_id, coordinates=combined_coords, constituent_track_ids=constituent_track_ids, length_meters=total_length if total_length > 0 else None, max_speed_kph=max_speed, status="operational", ) combined_track = combined_track_repo.create(create_data) session.commit() return CombinedTrackModel.model_validate(combined_track) def get_combined_track(session: Session, combined_track_id: str) -> CombinedTrackModel | None: """Get a combined track by ID.""" try: combined_track_repo = CombinedTrackRepository(session) combined_track = combined_track_repo.get(combined_track_id) return CombinedTrackModel.model_validate(combined_track) except LookupError: return None def list_combined_tracks(session: Session) -> list[CombinedTrackModel]: """List all combined tracks.""" combined_track_repo = CombinedTrackRepository(session) combined_tracks = combined_track_repo.list_all() return [CombinedTrackModel.model_validate(ct) for ct in combined_tracks]