use std::io::{self, Write};
use cstats_core::{api::types::AnthropicConfig, config::Config, Result};
use tracing::info;
use crate::{ConfigAction, ConfigArgs, OutputFormat};
use super::print_output;
pub async fn config_command(
args: ConfigArgs,
config: &Config,
format: OutputFormat,
config_path: Option<&std::path::Path>,
) -> Result<()> {
match args.action {
ConfigAction::Show => {
info!("Showing current configuration");
println!("Configuration loaded from:");
if std::env::var("ANTHROPIC_API_KEY").is_ok() {
println!(" ✓ ANTHROPIC_API_KEY environment variable");
}
if let Some(path) = config_path {
if path.exists() {
println!(" ✓ Config file: {}", path.display());
} else {
println!(" ⚠ Specified config file not found: {}", path.display());
}
} else if let Ok(default_path) = Config::default_config_path() {
if default_path.exists() {
println!(" ✓ Config file: {}", default_path.display());
} else {
println!(" ⚠ No config file found (using defaults)");
}
}
println!();
print_output(config, format)?;
}
ConfigAction::Validate => {
info!("Validating configuration");
match config.validate() {
Ok(()) => {
println!("✓ Configuration is valid");
if config.has_anthropic_api_key() {
println!("✓ Anthropic API key is configured");
} else {
println!("⚠ Anthropic API key is not configured");
println!(
" Set ANTHROPIC_API_KEY environment variable or run 'cstats init'"
);
}
if let Some(path) = config_path {
if path.exists() {
println!("✓ Config file found at: {}", path.display());
} else {
println!("⚠ Specified config file not found: {}", path.display());
}
} else if let Ok(default_path) = Config::default_config_path() {
if default_path.exists() {
println!("✓ Config file found at: {}", default_path.display());
} else {
println!(
"⚠ No config file found at default location: {}",
default_path.display()
);
println!(" Run 'cstats init' to create one");
}
}
}
Err(e) => {
println!("✗ Configuration validation failed:");
println!("{}", e);
return Err(e);
}
}
}
ConfigAction::Default => {
info!("Generating default configuration");
let default_config = Config::default();
print_output(&default_config, format)?;
}
ConfigAction::SetApiKey { api_key } => {
info!("Setting Anthropic API key");
let key = if let Some(key) = api_key {
key.clone()
} else {
prompt_for_api_key()?
.ok_or_else(|| cstats_core::Error::config("API key is required"))?
};
let config_path = Config::default_config_path()?;
let mut config = if config_path.exists() {
Config::load_from_file(&config_path).await?
} else {
Config::default()
};
let anthropic_config = AnthropicConfig {
api_key: key,
..config.api.anthropic.unwrap_or_default()
};
config.api.anthropic = Some(anthropic_config);
config.save_to_file(&config_path).await?;
println!("✓ Anthropic API key saved to: {}", config_path.display());
println!("You can now run 'cstats stats' to fetch usage statistics");
}
}
Ok(())
}
fn prompt_for_api_key() -> Result<Option<String>> {
print!("Enter your Anthropic API key: ");
io::stdout().flush().map_err(cstats_core::Error::from)?;
let mut input = String::new();
io::stdin()
.read_line(&mut input)
.map_err(cstats_core::Error::from)?;
let api_key = input.trim().to_string();
if api_key.is_empty() {
Ok(None)
} else if api_key.starts_with("sk-ant-") {
Ok(Some(api_key))
} else {
println!("⚠ Warning: API key doesn't match expected format (should start with 'sk-ant-')");
print!("Use anyway? (y/N): ");
io::stdout().flush().map_err(cstats_core::Error::from)?;
let mut confirm = String::new();
io::stdin()
.read_line(&mut confirm)
.map_err(cstats_core::Error::from)?;
if confirm.trim().to_lowercase() == "y" {
Ok(Some(api_key))
} else {
Ok(None)
}
}
}