1use comfy_table::{Table, ContentArrangement, presets::UTF8_FULL};
2
3use crate::model::SearchResult;
4
5fn format_price(price: Option<i64>, currency: &str) -> String {
6 let p = match price {
7 Some(p) => p,
8 None => return "—".to_string(),
9 };
10 match currency {
11 "USD" => format!("${p}"),
12 "EUR" => format!("€{p}"),
13 "GBP" => format!("£{p}"),
14 "JPY" | "CNY" => format!("¥{p}"),
15 "KRW" => format!("₩{p}"),
16 "INR" => format!("₹{p}"),
17 "THB" => format!("฿{p}"),
18 _ => format!("{p} {currency}"),
19 }
20}
21
22pub fn render(result: &SearchResult, currency: &str) -> String {
23 let mut table = Table::new();
24 table
25 .load_preset(UTF8_FULL)
26 .set_content_arrangement(ContentArrangement::Dynamic)
27 .set_header(vec![
28 "Airlines", "Route", "Depart", "Arrive", "Duration", "Stops", "Aircraft", "Price",
29 ]);
30
31 for flight in &result.flights {
32 let airlines = flight.airlines.join(", ");
33
34 let route: Vec<String> = flight
35 .segments
36 .iter()
37 .map(|s| format!("{} → {}", s.from_airport.code, s.to_airport.code))
38 .collect();
39 let route_str = route.join("\n");
40
41 let depart = flight
42 .segments
43 .first()
44 .map(|s| s.departure.to_string())
45 .unwrap_or_else(|| "—".to_string());
46
47 let arrive = flight
48 .segments
49 .last()
50 .map(|s| s.arrival.to_string())
51 .unwrap_or_else(|| "—".to_string());
52
53 let duration = if flight.segments.is_empty() {
54 "—".to_string()
55 } else {
56 let total_duration: u32 = flight.segments.iter().map(|s| s.duration_minutes).sum();
57 let hours = total_duration / 60;
58 let mins = total_duration % 60;
59 format!("{hours}h {mins:02}m")
60 };
61
62 let stops = if flight.segments.is_empty() {
63 "—".to_string()
64 } else if flight.segments.len() == 1 {
65 "Nonstop".to_string()
66 } else {
67 let n = flight.segments.len() - 1;
68 let stopovers: Vec<&str> = flight.segments[..flight.segments.len() - 1]
69 .iter()
70 .map(|s| s.to_airport.code.as_str())
71 .collect();
72 format!("{n} ({})", stopovers.join(", "))
73 };
74
75 let aircraft: Vec<String> = flight
76 .segments
77 .iter()
78 .filter_map(|s| s.aircraft.clone())
79 .collect();
80 let aircraft_str = aircraft.join(", ");
81
82 let price = format_price(flight.price, currency);
83
84 table.add_row(vec![
85 &airlines,
86 &route_str,
87 &depart,
88 &arrive,
89 &duration,
90 &stops,
91 &aircraft_str,
92 &price,
93 ]);
94 }
95
96 table.to_string()
97}