use crate::auth;
use crate::cli::LoginArgs;
use crate::client::ApiClient;
use crate::config::Config;
use crate::error::Result;
use crate::output::{print_success};
use dialoguer::{Input, Password};
pub async fn execute(args: &LoginArgs) -> Result<()> {
let config = Config::load().unwrap_or_default();
let server = args
.server
.clone()
.or_else(|| Some(config.server.url.clone()))
.unwrap_or_else(|| "http://localhost:38080".to_string());
let username = if let Some(u) = &args.username {
u.clone()
} else {
Input::new()
.with_prompt("Username")
.interact_text()
.map_err(|e| crate::error::CliError::InvalidInput(format!("Failed to read username: {}", e)))?
};
let password = if let Some(p) = &args.password {
p.clone()
} else {
Password::new()
.with_prompt("Password")
.interact()
.map_err(|e| crate::error::CliError::InvalidInput(format!("Failed to read password: {}", e)))?
};
let client = ApiClient::new(server.clone(), None)?;
print!("Logging in... ");
let login_response = client.login(&username, &password).await?;
let client_with_token = ApiClient::new(server.clone(), Some(login_response.access_token.clone()))?;
let user_info = client_with_token.get_me().await?;
let account_name = format!("{}@{}", username, extract_host(&server));
auth::save_account_with_role(
account_name.clone(),
server,
username.clone(),
login_response.access_token,
user_info.role.clone(),
true, )
.await?;
print_success(&format!("Logged in as {} (role: {})", username, user_info.role));
println!("Account saved as: {}", account_name);
Ok(())
}
fn extract_host(url: &str) -> String {
url.trim_start_matches("http://")
.trim_start_matches("https://")
.split(':')
.next()
.unwrap_or("localhost")
.to_string()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_extract_host() {
assert_eq!(extract_host("http://localhost:38080"), "localhost");
assert_eq!(extract_host("https://api.example.com"), "api.example.com");
assert_eq!(extract_host("http://192.168.1.1:8080"), "192.168.1.1");
}
}