use super::detection::strip_model_flag_prefix;
use super::types::OpenCodeProviderType;
#[must_use]
pub fn validate_model_flag(model_flag: &str) -> Vec<String> {
let model = strip_model_flag_prefix(model_flag);
if model.is_empty() {
return Vec::new();
}
if !model.contains('/') {
return vec![format!(
"Model '{model}' has no provider prefix. Expected format: 'provider/model' (e.g., 'opencode/glm-4.7-free')"
)];
}
let provider_type = OpenCodeProviderType::from_model_flag(model);
[
(provider_type == OpenCodeProviderType::OpenCodeZen
&& model.to_lowercase().contains("zai"))
.then_some(
"Model flag uses 'opencode/' prefix but contains 'zai'. \
For Z.AI Direct access, use 'zai/' prefix instead."
.to_string(),
),
provider_type.requires_cloud().then_some(format!(
"{} provider requires cloud configuration. {}",
provider_type.name(),
provider_type.auth_command()
)),
(provider_type == OpenCodeProviderType::Custom).then_some({
let prefix = model.split('/').next().unwrap_or("");
format!(
"Unknown provider prefix '{prefix}'. This may work if OpenCode supports it. \
Run 'ralph --list-providers' to see known providers."
)
}),
provider_type.is_local().then_some(format!(
"{} is a local provider. {}",
provider_type.name(),
provider_type.auth_command()
)),
]
.into_iter()
.flatten()
.collect()
}
#[must_use]
pub fn auth_failure_advice(model_flag: Option<&str>) -> String {
match model_flag {
Some(flag) => {
let model = strip_model_flag_prefix(flag);
let prefix = model.split('/').next().unwrap_or("").to_lowercase();
if matches!(prefix.as_str(), "zai" | "zhipuai") {
return "Authentication failed for Z.AI provider. Run: opencode auth login -> select 'Z.AI' or 'Z.AI Coding Plan'".to_string();
}
let provider = OpenCodeProviderType::from_model_flag(flag);
format!(
"Authentication failed for {} provider. Run: {}",
provider.name(),
provider.auth_command()
)
}
None => "Check API key or run 'opencode auth login' to authenticate.".to_string(),
}
}