use std::collections::HashMap;
use std::path::PathBuf;
use serde::{Deserialize, Serialize};
use crate::error::{Result, SxmcError};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BakeConfig {
pub name: String,
pub source_type: SourceType,
pub source: String,
pub auth_headers: Vec<String>,
pub env_vars: Vec<String>,
pub description: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum SourceType {
Stdio,
Http,
Api,
Spec,
Graphql,
}
pub struct BakeStore {
path: PathBuf,
configs: HashMap<String, BakeConfig>,
}
impl BakeStore {
pub fn load() -> Result<Self> {
let dir = dirs::config_dir()
.unwrap_or_else(|| PathBuf::from("~/.config"))
.join("sxmc");
std::fs::create_dir_all(&dir)
.map_err(|e| SxmcError::Other(format!("Failed to create config dir: {}", e)))?;
let path = dir.join("bakes.json");
let configs = if path.exists() {
let content = std::fs::read_to_string(&path)
.map_err(|e| SxmcError::Other(format!("Failed to read bakes: {}", e)))?;
serde_json::from_str(&content)?
} else {
HashMap::new()
};
Ok(Self { path, configs })
}
fn save(&self) -> Result<()> {
let json = serde_json::to_string_pretty(&self.configs)?;
std::fs::write(&self.path, json)
.map_err(|e| SxmcError::Other(format!("Failed to write bakes: {}", e)))?;
Ok(())
}
pub fn create(&mut self, config: BakeConfig) -> Result<()> {
if self.configs.contains_key(&config.name) {
return Err(SxmcError::Other(format!(
"Bake '{}' already exists. Use update or remove first.",
config.name
)));
}
self.configs.insert(config.name.clone(), config);
self.save()
}
pub fn update(&mut self, config: BakeConfig) -> Result<()> {
if !self.configs.contains_key(&config.name) {
return Err(SxmcError::Other(format!(
"Bake '{}' not found",
config.name
)));
}
self.configs.insert(config.name.clone(), config);
self.save()
}
pub fn remove(&mut self, name: &str) -> Result<()> {
if self.configs.remove(name).is_none() {
return Err(SxmcError::Other(format!("Bake '{}' not found", name)));
}
self.save()
}
pub fn get(&self, name: &str) -> Option<&BakeConfig> {
self.configs.get(name)
}
pub fn list(&self) -> Vec<&BakeConfig> {
let mut configs: Vec<_> = self.configs.values().collect();
configs.sort_by(|a, b| a.name.cmp(&b.name));
configs
}
pub fn show(&self, name: &str) -> Option<&BakeConfig> {
self.configs.get(name)
}
}
impl std::fmt::Display for BakeConfig {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} ({:?}: {})", self.name, self.source_type, self.source)?;
if let Some(ref desc) = self.description {
write!(f, " — {}", desc)?;
}
Ok(())
}
}