syntax = "proto3";

package worldmonitor.aviation.v1;

import "buf/validate/validate.proto";
import "sebuf/http/annotations.proto";
import "worldmonitor/aviation/v1/price_quote.proto";

// SearchFlightPricesRequest specifies parameters for a flight price search.
message SearchFlightPricesRequest {
  // Origin airport IATA code.
  string origin = 1 [
    (sebuf.http.query) = { name: "origin" },
    (buf.validate.field).required = true,
    (buf.validate.field).string.min_len = 3,
    (buf.validate.field).string.max_len = 4
  ];
  // Destination airport IATA code.
  string destination = 2 [
    (sebuf.http.query) = { name: "destination" },
    (buf.validate.field).required = true,
    (buf.validate.field).string.min_len = 3,
    (buf.validate.field).string.max_len = 4
  ];
  // Outbound departure date (ISO 8601).
  string departure_date = 3 [
    (sebuf.http.query) = { name: "departure_date" },
    (buf.validate.field).required = true,
    (buf.validate.field).string.len = 10
  ];
  // Return date (ISO 8601), empty for one-way.
  string return_date = 4 [(sebuf.http.query) = { name: "return_date" }];
  // Number of adult passengers (1-9).
  int32 adults = 5 [
    (sebuf.http.query) = { name: "adults" },
    (buf.validate.field).int32.gte = 1,
    (buf.validate.field).int32.lte = 9
  ];
  // Desired cabin class.
  CabinClass cabin = 6 [(sebuf.http.query) = { name: "cabin" }];
  // Whether to restrict to nonstop flights only.
  bool nonstop_only = 7 [(sebuf.http.query) = { name: "nonstop_only" }];
  // Maximum number of quotes to return (1-50).
  int32 max_results = 8 [
    (sebuf.http.query) = { name: "max_results" },
    (buf.validate.field).int32.gte = 1,
    (buf.validate.field).int32.lte = 50
  ];
  // ISO 4217 currency code for prices (e.g., "usd", "eur", "try").
  string currency = 9 [(sebuf.http.query) = { name: "currency" }];
  // Market/locale code (e.g., "us", "tr").
  string market = 10 [(sebuf.http.query) = { name: "market" }];
}

// SearchFlightPricesResponse contains flight price offers.
message SearchFlightPricesResponse {
  // Price quotes matching the search. Empty when degraded or no results.
  repeated PriceQuote quotes = 1;
  // Provider name: "travelpayouts_data", "demo", or "none" when no live
  // provider is configured.
  string provider = 2;
  // Whether results are from demo/simulated mode. Requires explicit
  // AVIATION_DEMO_PRICES=1 opt-in on the server. Never true in default
  // self-host / production runs. See issue #3756.
  bool is_demo_mode = 3;
  // Last update time as Unix epoch milliseconds.
  int64 updated_at = 4 [(sebuf.http.int64_encoding) = INT64_ENCODING_NUMBER];
  // Whether returned prices are indicative (subject to change).
  bool is_indicative = 5;
  // True when the live provider could not satisfy the request — missing
  // credentials, upstream failure, or zero results. Mirrors the
  // searchGoogleFlights pattern so clients can render distinct messages
  // for each error class.
  bool degraded = 6;
  // Discriminator for the degraded state: "" (ok), "missing_credentials"
  // (TRAVELPAYOUTS_API_TOKEN unset), "upstream_error" (provider call
  // threw), "no_results" (provider returned empty for this route).
  string error = 7;
}
