use std::collections::HashMap;
use anyhow::Result;
use serde::{Deserialize, Serialize};
use crate::{PromptStepType, replace_variables, render_prompt_interaction_with_vars};
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct SelectItem {
pub value: String,
pub label: String,
pub hint: Option<String>,
pub execute_yaml: Option<String>, }
#[derive(Debug, Deserialize, Serialize, Clone)]
#[serde(untagged)]
pub enum SelectItems {
Static(Vec<SelectItem>),
Variable(String),
}
pub fn handle_select(
step_type: &PromptStepType,
context: &mut HashMap<String, String>,
last_input: &mut Option<String>
) -> Result<()> {
if let PromptStepType::Select { prompt, items, output, initial } = step_type {
let mut select_builder = cliclack::select(prompt);
let resolved_items = match items {
SelectItems::Static(static_items) => static_items.clone(),
SelectItems::Variable(variable_ref) => {
let resolved_var = replace_variables(variable_ref, context, last_input);
if let Ok(items) = serde_json::from_str::<Vec<SelectItem>>(&resolved_var) {
items
} else if let Ok(config_map) = serde_json::from_str::<HashMap<String, String>>(&resolved_var) {
config_map.into_iter().map(|(key, value)| {
let hint = if value.len() > 50 {
format!("{}...", &value[..47])
} else {
value
};
SelectItem {
value: key.clone(),
label: key,
hint: Some(hint),
execute_yaml: None,
}
}).collect()
} else {
Vec::new()
}
}
};
if resolved_items.is_empty() {
return Err(anyhow::anyhow!("No items available for select"));
}
for item in &resolved_items {
let hint = item.hint.as_deref().unwrap_or("");
select_builder = select_builder.item(&item.value, &item.label, hint);
}
let resolved_initial_opt = initial.as_ref().map(|iv| replace_variables(iv, context, last_input));
if let Some(ref resolved_initial) = resolved_initial_opt {
select_builder = select_builder.initial_value(resolved_initial);
}
let selected_value: String = select_builder.interact()?.to_string();
let mut final_output_value = selected_value.clone();
if let Some(selected_item) = resolved_items.iter().find(|item| item.value == selected_value) {
if let Some(ref yaml_file) = selected_item.execute_yaml {
let variables: Vec<(&str, String)> = context.iter()
.map(|(k, v)| (k.as_str(), v.clone()))
.collect();
let result = render_prompt_interaction_with_vars(yaml_file, variables)?;
for (key, value) in &result {
context.insert(key.clone(), value.clone());
}
if let Some(external_output) = result.get("external_step_output") {
final_output_value = external_output.clone();
} else {
final_output_value = serde_json::to_string(&result).unwrap_or(selected_value);
}
}
}
if let Some(output_key) = output {
context.insert(output_key.clone(), final_output_value.clone());
*last_input = Some(final_output_value);
}
}
Ok(())
}