use anyhow::Result;
use chrono::NaiveDate;
use clap::Parser;
use gflights::parsers::common::{Location, PlaceType, TravelClass, Travelers};
use gflights::requests::api::ApiClient;
use gflights::requests::config::deals::DealConfig;
use super::OutputFormat;
#[derive(Parser, Debug)]
pub struct DealsArgs {
#[arg(long)]
pub from: String,
#[arg(long)]
pub out: NaiveDate,
#[arg(long)]
pub ret: NaiveDate,
#[arg(long)]
pub nonstop: bool,
#[arg(long)]
pub max_hours: Option<u32>,
#[arg(long, default_value = "1")]
pub adults: u32,
#[arg(long, default_value = "0")]
pub children: u32,
#[arg(long = "infants-seat", default_value = "0")]
pub infants_seat: u32,
#[arg(long = "infants-lap", default_value = "0")]
pub infants_lap: u32,
#[arg(long, default_value = "economy")]
pub class: TravelClass,
#[arg(long, default_value = "table")]
pub format: OutputFormat,
}
pub async fn cmd_deals(args: DealsArgs, client: &ApiClient) -> Result<()> {
let origin = Location {
loc_identifier: args.from.to_uppercase(),
loc_type: PlaceType::Airport,
location_name: None,
};
let travellers = Travelers::new(vec![
args.adults as i32,
args.children as i32,
args.infants_lap as i32,
args.infants_seat as i32,
])?;
let config = DealConfig {
origin: vec![origin],
outbound_date: args.out,
return_date: args.ret,
nonstop: args.nonstop,
max_duration_minutes: args.max_hours.map(|h| h * 60),
travel_class: args.class,
travellers,
};
let mut deals = client.request_deals(&config).await?;
deals.sort_by_key(|d| std::cmp::Reverse(d.discount_pct));
if deals.is_empty() {
eprintln!("No deals found.");
return Ok(());
}
match args.format {
OutputFormat::Json => {
println!("{}", serde_json::to_string_pretty(&deals)?);
}
OutputFormat::Table => {
println!(
"{:>5} {:>6} {:>7} {:<22} {:<8} {:>5} {:>5} {:<24}",
"OFF%", "PRICE", "TYPICAL", "DESTINATION", "AIRLINE", "STOPS", "MINS", "DATES"
);
println!("{}", "-".repeat(100));
for d in &deals {
let off = d
.discount_pct
.map(|p| format!("{p}%"))
.unwrap_or_else(|| "—".into());
let price = d.price.map(|p| p.to_string()).unwrap_or_else(|| "—".into());
let typical = d
.typical_price
.map(|p| p.to_string())
.unwrap_or_else(|| "—".into());
let dest = format!("{} ({})", d.destination_city, d.destination_iata);
let airline = d.airline_name.as_deref().unwrap_or("—");
let stops = d.stops.map(|s| s.to_string()).unwrap_or_else(|| "—".into());
let mins = d
.duration_minutes
.map(|m| m.to_string())
.unwrap_or_else(|| "—".into());
let dates = match (d.outbound_date, d.return_date) {
(Some(o), Some(r)) => format!("{o} → {r}"),
(Some(o), None) => o.to_string(),
_ => "—".into(),
};
println!(
"{:>5} {:>6} {:>7} {:<22} {:<8} {:>5} {:>5} {:<24}",
off, price, typical, dest, airline, stops, mins, dates
);
if let Some(url) = &d.booking_url {
println!(" {url}");
}
}
}
}
Ok(())
}