// Copyright 2026 MOIA GmbH

syntax = "proto3";

package moia.fleet.routing.v1beta3;

import "moia/type/v1/latlon.proto";

option go_package = "./routingv1beta3";
option java_multiple_files = false;
option java_outer_classname = "RoutingServiceV1Beta3";
option java_package = "io.moia.protos.fleet.routing.v1beta3";

// The RoutingService provides routing functionality for vehicles of a fleet.
service RoutingService {
  /**
   * Compute a route for the given request.
   *
   * Potential Errors:
   *
   * - INVALID_ARGUMENT: if the incoming request has missing or invalid fields
   * - PERMISSION_DENIED: if the client is not authorized to operate the given fleet
   * - NOT_FOUND: if no routing data is found for the given fleet
   * - FAILED_PRECONDITION: if routing data for the fleet is found but not configured in the routing server
   * - INTERNAL: internal error occurred
   */
  rpc ComputeRoute(ComputeRouteRequest) returns (ComputeRouteResponse) {}

  /**
   * Match a path to the road network and obtain a corresponding route.
   *
   * Potential Errors:
   *
   * - INVALID_ARGUMENT: if the incoming request has missing or invalid fields
   * - PERMISSION_DENIED: if the client is not authorized to operate the given fleet
   * - NOT_FOUND: if no routing data is found for the given fleet
   * - FAILED_PRECONDITION: if routing data for the fleet is found but not configured in the routing server
   * - INTERNAL: internal error occurred
   */
  rpc MatchPath(MatchPathRequest) returns (MatchPathResponse) {}

  /**
   * Compute a matrix of travel times between locations in the given request.
   * The response will be returned in a stream of chunks.
   * We do not guarantee any specific order of the response chunks.
   *
   * Since matrix computation can be computationally expensive, by default the API enforces a strict limit of at most 1000 matrix cells per second per account.
   * This also means that requests for matrices larger than that will be rejected (additionally to the limits placed on the request dimensions).
   * Reach out to the routing team if you want to use the matrix routing API with larger loads.
   *
   * Potential Errors:
   *
   * - INVALID_ARGUMENT: if the incoming request has missing or invalid fields
   * - RESOURCE_EXHAUSTED: if the client currently exceeded its quota
   * - PERMISSION_DENIED: if the client is not authorized to operate the given fleet
   * - NOT_FOUND: if no routing data is found for the given fleet
   * - FAILED_PRECONDITION: if routing data for the fleet is found but not configured in the routing server
   * - INTERNAL: internal error occurred
   */
  rpc ComputeTravelTimeMatrix(ComputeTravelTimeMatrixRequest) returns (stream ComputeTravelTimeMatrixResponse) {}

  /**
   * Compute a matrix of travel times between locations in the given request in the background.
   * This method will immediately return without waiting for the computation to finish.
   * The returned reference can be used to download the data by calling `DownloadTravelTimeMatrix` during the following 24 hours.
   *
   * Since matrix computation can be computationally expensive, by default the API enforces strict limits.
   * Reach out to the routing team if you want to use the matrix routing API with larger loads.
   *
   * Potential Errors:
   *
   * - INVALID_ARGUMENT: if the incoming request has missing or invalid fields
   * - UNAVAILABLE: if the matrix data storage backend is not available
   * - PERMISSION_DENIED: if the client is not authorized to operate the given fleet
   * - NOT_FOUND: if no routing data is found for the given fleet
   * - FAILED_PRECONDITION: if routing data for the fleet is found but not configured in the routing server
   * - INTERNAL: internal error occurred
   */
  rpc ComputeTravelTimeMatrixAsynchronously(ComputeTravelTimeMatrixAsynchronouslyRequest) returns (ComputeTravelTimeMatrixAsynchronouslyResponse) {}

  /**
   * Download a matrix of travel times previously computed with `ComputeTravelTimeMatrixAsynchronously`.
   * The response will be returned in a stream of chunks.
   * We do not guarantee any specific order of the response chunks.
   * If matrix computation is still ongoing, this call will return chunks as they become available.
   * It may block while chunks are still being computed/stored.
   * Once the full matrix was transmitted, the stream will be closed.
   *
   * Potential Errors:
   *
   * - INVALID_ARGUMENT: if the incoming request has missing or invalid fields
   * - NOT_FOUND: if no data is available under the given reference (because the reference is unknown or the data was already deleted)
   * - UNAVAILABLE: if the matrix data storage backend is not available
   * - DATA_LOSS: the stored matrix data is incomplete or corrupted. Retry computing the matrix with `ComputeTravelTimeMatrixAsynchronously`
   * - PERMISSION_DENIED: if the client is not authorized to access matrix data for the given fleet
   * - INTERNAL: internal error occurred
   */
  rpc DownloadTravelTimeMatrix(DownloadTravelTimeMatrixRequest) returns (stream DownloadTravelTimeMatrixResponse) {}
}

// A request for a route that traverses two or more waypoints.
message ComputeRouteRequest {
  // The origin of the route (required).
  RoutingWaypoint origin = 1;

  // The destination of the route (required).
  RoutingWaypoint destination = 2;

  // Zero or more via waypoints that must be traversed in the given order.
  // The API currently allows at most 100 via points.
  repeated RoutingWaypoint via = 3;

  // Properties of the vehicle that should be routed (required).
  VehicleConfiguration vehicle_configuration = 4;

  // Determines the geographic region, map data set and additional parameters used for routing (required).
  oneof routing_context {
    // The ID of a specific vehicle.
    string vehicle_id = 5;
    // The ID of a fleet.
    string fleet_id = 6;
    // The ID of an operating area.
    string operating_area_id = 7;
  }

  // The measure that is minimized during routing.
  optional OptimizationCriterion optimization_criterion = 8;

  // Additional output data to include in the response legs.
  // By default only geometry is returned.
  repeated OutputOption output_options = 9;
}

// A response to a ComputeRoute request.
message ComputeRouteResponse {
  // The content of the response.
  oneof content {
    // The route that traverses the requested waypoints.
    Route route = 1;

    // The reason that prevented a route from being computed.
    NoRouteFoundReason no_route_found = 2;
  }
}

// A request to match a path to the road network and obtain a corresponding route.
message MatchPathRequest {
  // Determines the geographic region, map data set and additional parameters used for routing (required).
  oneof routing_context {
    // The ID of a specific vehicle.
    string vehicle_id = 1;
    // The ID of a fleet.
    string fleet_id = 2;
    // The ID of an operating area.
    string operating_area_id = 3;
  }

  // A polyline that describes the path. The polyline must contain at least two locations (required).
  repeated moia.type.v1.LatLon path = 4;

  // Properties of the vehicle that is targeted (required).
  VehicleConfiguration vehicle_configuration = 5;

  // Additional output data to include in the response leg.
  // By default only geometry is returned.
  repeated OutputOption output_options = 6;
}

// A response to a MatchPath request.
message MatchPathResponse {
  // The content of the response.
  oneof content {
    // The route that best corresponds to the provided path.
    // Since it will always consist of exactly one section, we return a single `LegOrLegWithViolations` instead of a `Route`.
    LegOrLegWithViolations leg = 1;

    // The reason that prevented a path from being matched.
    PathNotMatchedReason path_not_matched_reason = 2;
  }
}

// A request for a matrix of travel times between multiple origins and destinations.
// The API currently allows computation of matrices with up to 1000x20000 locations (or 20000x1000),
// i.e. the larger dimension must be 20000 or less and the smaller 1000 or less.
message ComputeTravelTimeMatrixRequest {
  // The set of origins to compute travel times from (required).
  repeated RoutingWaypoint origins = 1;

  // The set of destinations to compute travel times to (required).
  repeated RoutingWaypoint destinations = 2;

  // Properties of the vehicle that should be routed (required).
  VehicleConfiguration vehicle_configuration = 3;

  // Determines the geographic region, map data set and additional parameters used for routing (required).
  oneof routing_context {
    // The ID of a fleet.
    string fleet_id = 4;
    // The ID of an operating area.
    string operating_area_id = 5;
  }

  // The measure that is minimized during routing.
  optional OptimizationCriterion optimization_criterion = 6;
}

// A chunk of the response to the ComputeTravelTimeMatrix call.
message ComputeTravelTimeMatrixResponse {
  // The start index of the entries contained in this chunk.
  int32 entries_offset = 1;

  // (A chunk of) the matrix of travel times in seconds.
  // The combined chunks yield a matrix in row-major order.
  // Rows correspond to origins and columns correspond to destinations.
  // That is, the travel time from the origin with index i to the destination with index j
  // is stored at the travel time entry with index (i*num_destinations + j).
  // A chunk contains the entries with indices `[entries_offset, entries_offset + len(travel_times_seconds))`.
  repeated int32 travel_times_seconds = 2;

  // Lists all entry indices for which no violation-free route could be computed.
  // That means the best route between the respective origin and destination
  // violates one or more legal, physical, or user-defined restrictions.
  // No route without violations could be found.
  // Possible violations include, for example, passing through zones that forbid through traffic or using blocked roads.
  // The travel time of the entry is still valid but the associated route likely cannot be driven.
  //
  // Note that the indices in this list refer to the entries of this chunk.
  // To obtain indices with respect to the complete matrix, the `entries_offset` must be added to each index.
  repeated int32 violating_entries_indices = 3;

  // Lists all entry indices for which no travel time could be computed.
  // If an entry is included here, its travel time is invalid and must not be used.
  //
  // Note that the indices in this list refer to the entries of this chunk.
  // To obtain indices with respect to the complete matrix, the `entries_offset` must be added to each index.
  repeated int32 no_route_found_entries_indices = 4;

  // Lists for every entry in `no_route_found_entries_indices` the reason that prevented the travel time from being computed.
  repeated NoRouteFoundReason no_route_found_entries_reasons = 5;
}

// A request for asynchronous travel time matrix computation.
message ComputeTravelTimeMatrixAsynchronouslyRequest {
  // The request data.
  // See `ComputeTravelTimeMatrixRequest`.
  ComputeTravelTimeMatrixRequest request = 1;
}

// A response to an asynchronous travel time matrix computation call.
message ComputeTravelTimeMatrixAsynchronouslyResponse {
  // An id which can be used to reference the computed matrix for successive download.
  string matrix_id = 1;
}

// A request for downloading an asynchronously computed travel time matrix.
message DownloadTravelTimeMatrixRequest {
  // The matrix id from the `ComputeTravelTimeMatrixAsynchronouslyResponse`.
  string matrix_id = 1;
}

// A response (chunk) of the `DownloadTravelTimeMatrix` call.
message DownloadTravelTimeMatrixResponse {
  // The start index of the entries contained in this chunk.
  int32 entries_offset = 1;

  // (A chunk of) the matrix of travel times in seconds.
  // The combined chunks yield a matrix in row-major order.
  // Rows correspond to origins and columns correspond to destinations.
  // That is, the travel time from the origin with index i to the destination with index j
  // is stored at the travel time entry with index (i*num_destinations + j).
  // A chunk contains the entries with indices `[entries_offset, entries_offset + len(travel_times_seconds))`.
  repeated int32 travel_times_seconds = 2;

  // Lists all entry indices for which no violation-free route could be computed.
  // That means the best route between the respective origin and destination
  // violates one or more legal, physical, or user-defined restrictions.
  // No route without violations could be found.
  // Possible violations include, for example, passing through zones that forbid through traffic or using blocked roads.
  // The travel time of the entry is still valid but the associated route likely cannot be driven.
  //
  // Note that the indices in this list refer to the entries of this chunk.
  // To obtain indices with respect to the complete matrix, the `entries_offset` must be added to each index.
  repeated int32 violating_entries_indices = 3;

  // Lists all entry indices for which no travel time could be computed.
  // If an entry is included here, its travel time is invalid and must not be used.
  //
  // Note that the indices in this list refer to the entries of this chunk.
  // To obtain indices with respect to the complete matrix, the `entries_offset` must be added to each index.
  repeated int32 no_route_found_entries_indices = 4;

  // Lists for every entry in `no_route_found_entries_indices` the reason that prevented the travel time from being computed.
  repeated NoRouteFoundReason no_route_found_entries_reasons = 5;
}

// A location that a route must traverse, with an optional heading to indicate direction of travel.
message RoutingWaypoint {
  // The latitude in degrees.
  // [-90.0, +90.0].
  double latitude = 1;
  // The longitude in degrees.
  // [-180.0, +180.0].
  double longitude = 2;
  // The horizontal direction in degrees, measured clockwise from north.
  // [0.0, 360.0).
  // The interval is half-closed; 360.0° is invalid, use 0.0° instead.
  // 0.0° = facing north, 90.0° = facing east, 180.0° = facing south, 270.0° = facing west.
  optional double heading = 3;
}

// Properties of a vehicle.
message VehicleConfiguration {
  // Whether the vehicle is an autonomous vehicle.
  bool self_driving = 1;
}

// The optimization criterion defines if travel time or distance is minimized during routing.
// Note that the result may not be the route with the strictly minimal value for the criterion as the service tries to
// avoid certain problematic route features such as U-turns or driving through inconvenient side roads etc.
enum OptimizationCriterion {
  // A special value to indicate that a field is not set.
  OPTIMIZATION_CRITERION_UNSPECIFIED = 0;

  // Travel time is used as the main objective to be minimized during routing.
  // Used by default when nothing else is specified.
  OPTIMIZATION_CRITERION_TIME = 1;

  // Driving distance is used as the main objective to be minimized during routing.
  OPTIMIZATION_CRITERION_DISTANCE = 2;
}

// A route from origin to destination traversing all given via locations (if any) in the specified order.
// It consists of one or more legs, each connecting two consecutive waypoints.
message Route {
  // The route sections that make up the route.
  repeated LegOrLegWithViolations legs = 1;
}

// This message is a container for leg data.
// It may consist either of a plain leg or alternatively, of a leg with violations.
// The service only responds with a leg with violations if no alternative route without violations exists.
// A leg with violations means that a route could be computed but it may be problematic
// and must be carefully considered in the context of the service consumer's use case.
// Most violations indicate that it is illegal or impossible to drive a leg according to our routing data.
// Consider the ViolationType of the respective violations for more details on the severity of the problem.
message LegOrLegWithViolations {
  // The content of this message.
  oneof content {
    // An unproblematic route leg.
    Leg leg = 1;
    // A route leg with violations.
    // In this case, consumers of the routing service must carefully evaluate if the leg is usable for their purposes.
    LegWithViolation leg_with_violation = 2;
  }
}

// A route leg that violates routing restrictions.
message LegWithViolation {
  // The route leg.
  Leg leg = 1;
  // Restrictions violated by the leg.
  repeated Violation violations = 2;
}

// A leg represents the part of a route between two consecutive waypoints
// and contains the coordinates, travel time and length of that part.
message Leg {
  // The time to traverse the leg in seconds.
  int32 travel_time_seconds = 1;

  // The length of the leg in meters.
  int32 length_meters = 2;

  // A polyline that describes the geometry of the leg.
  repeated moia.type.v1.LatLon geometry = 3;

  // Road segments making up this leg.
  // Only present if OUTPUT_OPTION_SEGMENTS was requested.
  optional Segments segments = 4;

  // OpenLR-encoded representation of this leg.
  // Only present if OUTPUT_OPTION_OPEN_LR was requested.
  optional string open_lr = 5;
}

// The road segments traversed by a route leg, with entry and exit offsets.
message Segments {
  // The road segments in traversal order.
  repeated Segment segments = 1;

  // The fractional offset along the first segment at which the leg begins.
  // [0.0, 1.0], where 0.0 is the start of the segment and 1.0 is the end.
  double start_offset_on_segment = 2;

  // The fractional offset along the last segment at which the leg ends.
  // [0.0, 1.0], where 0.0 is the start of the segment and 1.0 is the end.
  double end_offset_on_segment = 3;
}

// A single road segment traversed by a route leg.
message Segment {
  // The ID of the road segment.
  string segment_id = 1;

  // The index in the leg's geometry polyline at which this segment starts.
  int32 geometry_start_index = 2;

  // The number of successive geometry coordinates covered by this segment.
  int32 geometry_coordinates_count = 3;
}

// A violation indicates an issue with a route leg.
// While a route could be computed, the leg violates a routing restriction.
message Violation {
  // Describes the kind of underlying problem.
  ViolationType violation_type = 1;

  // The index in the leg's polyline at which the geometry of this violation starts.
  int32 start_index = 2;

  // The number of successive coordinates making up the geometry of this violation.
  // A zero would indicate that a violation has no geometry, a one that it consists of a singular point.
  int32 coordinates_count = 3;
}

// A ViolationType describes the kind of problem of a specific violation.
enum ViolationType {
  // A special value to indicate that a field is not set.
  VIOLATION_TYPE_UNSPECIFIED = 0;

  // The leg departs at the origin in a different direction than requested.
  VIOLATION_TYPE_WRONG_DIRECTION_AT_ORIGIN = 1;

  // The leg arrives at the destination in a different direction than requested.
  VIOLATION_TYPE_WRONG_DIRECTION_AT_DESTINATION = 2;

  // The leg passes through a zone that forbids through traffic.
  VIOLATION_TYPE_INTERMEDIATE_LOCAL_ZONE_USED = 3;

  // The leg uses one or more blocked roads.
  VIOLATION_TYPE_BLOCKED_ROAD_USED = 4;

  // The leg uses a road where driving is disallowed at the current time.
  VIOLATION_TYPE_TIME_DEPENDENT_RESTRICTION_VIOLATED = 5;

  // The leg contains roads which cannot be driven with a vehicle of the specified configuration.
  VIOLATION_TYPE_ROAD_FORBIDDEN_FOR_VEHICLE_CONFIGURATION_USED = 6;

  // The leg contains a turn which is illegal (or impossible) to take.
  VIOLATION_TYPE_FORBIDDEN_TURN_USED = 7;

  // The leg contains a turn which cannot be driven with a vehicle of the specified configuration.
  VIOLATION_TYPE_TURN_FORBIDDEN_FOR_VEHICLE_CONFIGURATION_USED = 8;
}

// An issue that prevented a route from being computed.
enum NoRouteFoundReason {
  // A special value to indicate that a field is not set.
  NO_ROUTE_FOUND_REASON_UNSPECIFIED = 0;

  // A waypoint could not be matched to the road network, i.e. our map data contains no usable
  // road within reasonable distance of the location for the given vehicle configuration.
  NO_ROUTE_FOUND_REASON_COULD_NOT_MATCH_WAYPOINT = 1;

  // A waypoint was not reachable from the preceding waypoint.
  NO_ROUTE_FOUND_REASON_COULD_NOT_REACH_WAYPOINT = 2;
}

// Controls which additional data is included in route leg responses.
enum OutputOption {
  // A special value to indicate that a field is not set.
  OUTPUT_OPTION_UNSPECIFIED = 0;

  // Include road segments for each leg.
  OUTPUT_OPTION_SEGMENTS = 1;

  // Include an OpenLR-encoded representation of each leg.
  OUTPUT_OPTION_OPEN_LR = 2;
}

// An issue that prevented a path from being matched.
enum PathNotMatchedReason {
  // A special value to indicate that a field is not set.
  PATH_NOT_MATCHED_REASON_UNSPECIFIED = 0;

  // For the given vehicle configuration, our map data does not contain a path
  // which stays within reasonable distance to the provided geometry.
  PATH_NOT_MATCHED_REASON_COULD_NOT_MATCH_PATH = 1;
}
