nsg-cli 0.1.2

CLI tool for the Neuroscience Gateway (NSG) BRAIN Initiative API
Documentation
use crate::client::NsgClient;
use crate::config::Credentials;
use anyhow::Result;
use clap::Args;
use colored::Colorize;

#[derive(Debug, Args)]
pub struct StatusCommand {
    #[arg(help = "Job URL or Job ID")]
    job: String,
}

impl StatusCommand {
    pub fn execute(self) -> Result<()> {
        let credentials = Credentials::load()?;
        let client = NsgClient::new(credentials)?;

        println!("{}", "NSG Job Status".bold().cyan());
        println!("{}", "=".repeat(80).cyan());
        println!();
        println!("{} Checking job status...", "".cyan());
        println!("   Job: {}", self.job.bold());
        println!();

        let status = client.get_job_status(&self.job)?;

        println!("{} Job found", "".green().bold());
        println!();
        println!("{}", "Job Status Information".bold());
        println!("{}", "=".repeat(80));
        println!();
        println!("Job ID:       {}", status.job_id.cyan());

        let stage_icon = get_stage_icon(&status.job_stage);
        println!("Stage:        {} {}", stage_icon, status.job_stage.bold());

        if status.failed {
            println!("Failed:       {} YES", "".red().bold());
        }

        if let Some(date) = &status.date_submitted {
            println!("Submitted:    {}", format_timestamp(date));
        }

        if status.results_uri.is_some() {
            println!("Results:      {} Available", "".green());
        } else {
            println!("Results:      {} Not yet available", "".yellow());
        }

        if !status.messages.is_empty() {
            println!();
            println!("{}", "Recent Messages:".bold());
            let recent = if status.messages.len() > 5 {
                &status.messages[status.messages.len() - 5..]
            } else {
                &status.messages[..]
            };

            for msg in recent {
                println!();
                println!(
                    "  [{}] {}",
                    msg.stage.cyan(),
                    msg.timestamp.as_deref().unwrap_or("")
                );
                if !msg.text.is_empty() {
                    let text = if msg.text.len() > 200 {
                        format!("{}...", &msg.text[..200])
                    } else {
                        msg.text.clone()
                    };
                    println!("    {}", text);
                }
            }
        }

        println!();
        println!("{}", "=".repeat(80));
        println!();

        print_next_action(&status.job_stage, &self.job);

        Ok(())
    }
}

fn get_stage_icon(stage: &str) -> &'static str {
    match stage {
        "COMPLETED" => "",
        "RUNNING" | "RUN" => "",
        "QUEUE" | "SUBMITTED" => "",
        "FAILED" => "",
        _ => "?",
    }
}

fn format_timestamp(ts: &str) -> String {
    use chrono::{DateTime, Utc};
    if let Ok(dt) = ts.parse::<DateTime<Utc>>() {
        dt.format("%Y-%m-%d %H:%M:%S UTC").to_string()
    } else {
        ts.to_string()
    }
}

fn print_next_action(stage: &str, job_id: &str) {
    match stage {
        "COMPLETED" => {
            println!(
                "{} Job completed! You can now download results.",
                "".green().bold()
            );
            println!();
            println!("To download all results:");
            println!("  {}", format!("nsg download {}", job_id).cyan());
        }
        "FAILED" => {
            println!(
                "{} Job failed. Check messages above for error details.",
                "".red().bold()
            );
        }
        "QUEUE" | "SUBMITTED" => {
            println!("{} Job is queued. Check again later.", "".yellow());
            println!();
            println!("To check status again:");
            println!("  {}", format!("nsg status {}", job_id).cyan());
        }
        "RUN" | "RUNNING" => {
            println!(
                "{} Job is running. Check back later for completion.",
                "".yellow()
            );
            println!();
            println!("To check status again:");
            println!("  {}", format!("nsg status {}", job_id).cyan());
        }
        _ => {
            println!("{} Unknown job stage: {}", "?".yellow(), stage);
        }
    }
    println!();
}