use chrono::{DateTime, Utc};
use crate::types::{pricing_key, ModelPricing, PricingTable};
fn to_plan(p: &tt_shared::pricing::ModelPricing) -> ModelPricing {
ModelPricing {
input_per_million: p.input_per_million,
output_per_million: p.output_per_million,
cached_input_per_million: p.cached_input_per_million,
}
}
#[must_use]
pub fn catalog_pricing_table() -> PricingTable {
let catalog = tt_shared::pricing::catalog();
let mut table = PricingTable::new();
for (provider, model) in catalog.pairs() {
if let Some(p) = catalog.latest(&provider, &model) {
table.insert(pricing_key(&provider, &model), to_plan(&p));
}
}
table
}
#[must_use]
pub fn catalog_pricing_table_at(at: DateTime<Utc>) -> PricingTable {
let catalog = tt_shared::pricing::catalog();
let mut table = PricingTable::new();
for (provider, model) in catalog.pairs() {
if let Some(p) = catalog.at(&provider, &model, at) {
table.insert(pricing_key(&provider, &model), to_plan(&p));
}
}
table
}
#[cfg(test)]
mod tests {
use super::*;
use chrono::TimeZone;
#[test]
fn catalog_table_is_populated_and_keyed_provider_model() {
let table = catalog_pricing_table();
assert!(!table.is_empty(), "shared catalog should yield rows");
let p = table
.get(&pricing_key("openai", "gpt-4o"))
.expect("openai:gpt-4o should be in the catalog table");
assert_eq!(p.input_per_million, 2.50);
assert_eq!(p.output_per_million, 10.00);
assert_eq!(p.cached_input_per_million, Some(1.25));
}
#[test]
fn at_time_table_matches_latest_for_single_history() {
let after = Utc.with_ymd_and_hms(2026, 6, 1, 0, 0, 0).unwrap();
let live = catalog_pricing_table();
let hist = catalog_pricing_table_at(after);
let key = pricing_key("anthropic", "claude-sonnet-4-6");
assert_eq!(
live.get(&key).map(|p| p.input_per_million),
hist.get(&key).map(|p| p.input_per_million),
);
}
}