use crate::selectors::error::{SelectorError, SelectorResult};
use crate::{
credentials::CredentialStore,
templates::{TemplateType, get_template_instance},
};
pub struct TemplateSelector;
impl TemplateSelector {
pub fn select_template() -> SelectorResult<TemplateType> {
let template_types = [
TemplateType::DeepSeek,
TemplateType::Zai,
TemplateType::KatCoder,
TemplateType::Kimi,
TemplateType::Longcat,
TemplateType::Fishtrip,
TemplateType::MiniMax,
TemplateType::SeedCode,
TemplateType::Zenmux,
TemplateType::Duojie,
TemplateType::AnyRouter,
];
let options: Vec<String> = template_types.iter().map(|t| t.to_string()).collect();
let selection = inquire::Select::new("Select AI provider:", options)
.with_help_message("↑/↓: Navigate, Enter: Select, Esc: Cancel")
.prompt()
.map_err(inquire_to_selector_error)?;
template_types
.into_iter()
.find(|t| t.to_string() == selection)
.ok_or(SelectorError::NotFound)
}
pub fn get_api_key_for_template(template_type: TemplateType) -> SelectorResult<Option<String>> {
crate::selectors::credential::CredentialSelector::select_api_key(template_type)
}
pub fn get_endpoint_id_for_template(
template_type: &TemplateType,
) -> SelectorResult<Option<String>> {
let template_instance = get_template_instance(template_type);
if !template_instance.requires_additional_config() {
return Ok(None);
}
let endpoint_ids = CredentialStore::new()
.map(|store| store.get_endpoint_ids(template_type))
.unwrap_or_default();
if endpoint_ids.is_empty() {
return Self::prompt_endpoint_id(template_type);
}
let mut options = vec!["Enter new endpoint ID...".to_string()];
for (display_name, _) in &endpoint_ids {
options.push(display_name.clone());
}
let selection =
inquire::Select::new(&format!("Select {} endpoint ID:", template_type), options)
.with_help_message("↑/↓: Navigate, Enter: Select, Esc: Cancel")
.prompt()
.map_err(inquire_to_selector_error)?;
if selection == "Enter new endpoint ID..." {
Self::prompt_endpoint_id(template_type)
} else {
endpoint_ids
.into_iter()
.find(|(name, _)| name == &selection)
.map(|(_, id)| Some(id))
.ok_or(SelectorError::NotFound)
}
}
fn prompt_endpoint_id(template_type: &TemplateType) -> SelectorResult<Option<String>> {
let template_instance = get_template_instance(template_type);
if let Some(url) = template_instance.api_key_url() {
println!(" Get your endpoint ID from: {}", url);
}
let endpoint_id = inquire::Text::new(&format!("Enter {} endpoint ID:", template_type))
.with_placeholder("ep-xxx-xxx")
.prompt()
.map_err(inquire_to_selector_error)?;
if endpoint_id.trim().is_empty() {
Err(SelectorError::InvalidInput(
"Endpoint ID cannot be empty".to_string(),
))
} else {
Ok(Some(endpoint_id))
}
}
}
fn inquire_to_selector_error(e: inquire::InquireError) -> SelectorError {
let msg = e.to_string();
if msg.contains("canceled") || msg.contains("cancelled") {
SelectorError::Cancelled
} else {
SelectorError::Failed(msg)
}
}
pub fn get_endpoint_id_interactively(template_type: &TemplateType) -> SelectorResult<String> {
match TemplateSelector::get_endpoint_id_for_template(template_type)? {
Some(endpoint_id) => Ok(endpoint_id),
None => Err(SelectorError::NotFound),
}
}