use std::{
io::{self, Write},
path::PathBuf,
};
use cstats_core::{api::types::AnthropicConfig, config::Config, Result};
use crate::InitArgs;
pub async fn init_command(args: InitArgs) -> Result<()> {
let config_path = args.config.unwrap_or_else(|| {
Config::default_config_path().unwrap_or_else(|_| {
let home_dir = std::env::var("HOME").unwrap_or_else(|_| ".".to_string());
PathBuf::from(format!("{}/.cstats/config.json", home_dir))
})
});
let mut config = if config_path.exists() && !args.force {
match Config::load_from_file(&config_path).await {
Ok(existing) => {
println!(
"✓ Found existing configuration at: {}",
config_path.display()
);
existing
}
Err(_) => {
println!(
"⚠ Could not read existing config at: {}",
config_path.display()
);
println!(" Creating new configuration...");
Config::default()
}
}
} else if config_path.exists() && args.force {
println!(
"⚠ Overwriting existing configuration at: {}",
config_path.display()
);
Config::default()
} else {
Config::default()
};
let needs_api_key = config
.api
.anthropic
.as_ref()
.map(|a| a.api_key.is_empty())
.unwrap_or(true);
if needs_api_key {
if let Some(api_key) = args.api_key {
let anthropic_config = if let Some(mut existing) = config.api.anthropic {
existing.api_key = api_key;
existing
} else {
AnthropicConfig {
api_key,
..Default::default()
}
};
config.api.anthropic = Some(anthropic_config);
println!("✓ Anthropic API key configured from argument");
} else if std::env::var("ANTHROPIC_API_KEY").is_ok() {
println!("✓ Using ANTHROPIC_API_KEY from environment");
} else {
println!("Setting up Anthropic API configuration...");
if let Some(api_key) = prompt_for_api_key()? {
let anthropic_config = if let Some(mut existing) = config.api.anthropic {
existing.api_key = api_key;
existing
} else {
AnthropicConfig {
api_key,
..Default::default()
}
};
config.api.anthropic = Some(anthropic_config);
println!("✓ Anthropic API key configured");
} else {
println!("⚠ Skipping Anthropic API key setup. You can:");
println!(" - Set ANTHROPIC_API_KEY environment variable");
println!(" - Run 'cstats config set-api-key'");
println!(
" - Edit the config file manually: {}",
config_path.display()
);
}
}
} else {
println!("✓ API key already configured, preserving existing settings");
}
config.save_to_file(&config_path).await?;
println!(
"\n✓ Initialized cstats configuration at: {}",
config_path.display()
);
println!("\nNext steps:");
println!(" - Run 'cstats config show' to view your configuration");
println!(" - Run 'cstats stats' to fetch your Claude Code usage statistics");
if !config.has_anthropic_api_key() {
println!(" - Configure your Anthropic API key to enable stats collection");
}
Ok(())
}
fn prompt_for_api_key() -> Result<Option<String>> {
print!("Enter your Anthropic API key (or press Enter to skip): ");
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)
}
}
}