vex-cli 0.7.13

AI-native version control workflow engine
use serde_json::json;

use crate::daemon_client;

pub fn create(
    project_name: &str,
    name: Option<&str>,
    branch: Option<&str>,
    pr: Option<&str>,
    host: Option<&str>,
) {
    let mut client = daemon_client::connect_to_hub_or_exit();

    let ws_name = match (name, pr) {
        (Some(n), _) => n.to_string(),
        (None, Some(_pr_url)) => {
            // TODO: resolve PR branch via daemon when workstream.create supports --pr
            eprintln!("Error: provide a workstream name or --pr <url>");
            std::process::exit(1);
        }
        (None, None) => {
            eprintln!("Error: provide a workstream name or --pr <url>");
            std::process::exit(1);
        }
    };

    let mut params = json!({"project": project_name, "name": ws_name});
    if let Some(b) = branch {
        params["branch"] = json!(b);
    }
    if let Some(h) = host {
        params["host"] = json!(h);
    }

    match client.request("workstream.create", params) {
        Ok(result) => {
            let name = result.get("name").and_then(|v| v.as_str()).unwrap_or("-");
            let branch = result.get("branch").and_then(|v| v.as_str()).unwrap_or("-");
            println!("Created workstream '{name}' on branch '{branch}'");
        }
        Err(e) => {
            eprintln!("Error: {e}");
            std::process::exit(1);
        }
    }
}

pub fn rename(project_name: &str, name: &str, new_name: &str, host: Option<&str>) {
    let mut client = daemon_client::connect_to_hub_or_exit();

    let mut params = json!({"project": project_name, "name": name, "new_name": new_name});
    if let Some(h) = host {
        params["host"] = json!(h);
    }

    match client.request("workstream.rename", params) {
        Ok(result) => {
            let ws_name = result.get("name").and_then(|v| v.as_str()).unwrap_or("-");
            let branch = result.get("branch").and_then(|v| v.as_str()).unwrap_or("-");
            println!("Renamed workstream '{name}' -> '{ws_name}' (branch: {branch})");
        }
        Err(e) => {
            eprintln!("Error: {e}");
            std::process::exit(1);
        }
    }
}

pub fn list(project_name: &str, host: Option<&str>) {
    let mut client = daemon_client::connect_to_hub_or_exit();

    let mut params = json!({"project": project_name});
    if let Some(h) = host {
        params["host"] = json!(h);
    }

    match client.request("workstream.list", params) {
        Ok(result) => {
            let workstreams = result.as_array().cloned().unwrap_or_default();
            if workstreams.is_empty() {
                println!("No workstreams for project '{project_name}'.");
                return;
            }
            println!("{:<12} {:<20} {:<30} STATE", "HOST", "NAME", "BRANCH");
            println!("{}", "─".repeat(72));
            for ws in &workstreams {
                println!(
                    "{:<12} {:<20} {:<30} {}",
                    ws.get("host").and_then(|v| v.as_str()).unwrap_or("-"),
                    ws.get("name").and_then(|v| v.as_str()).unwrap_or("-"),
                    ws.get("branch").and_then(|v| v.as_str()).unwrap_or("-"),
                    ws.get("state").and_then(|v| v.as_str()).unwrap_or("-"),
                );
            }
        }
        Err(e) => {
            eprintln!("Error: {e}");
            std::process::exit(1);
        }
    }
}

pub fn notes_get(project_name: &str, ws_name: &str, host: Option<&str>) {
    let mut client = daemon_client::connect_to_hub_or_exit();

    let mut params = json!({"project": project_name, "name": ws_name});
    if let Some(h) = host {
        params["host"] = json!(h);
    }

    match client.request("workstream.get-notes", params) {
        Ok(result) => {
            let notes = result.get("notes").and_then(|v| v.as_str()).unwrap_or("");
            if notes.is_empty() {
                println!("(no notes)");
            } else {
                print!("{notes}");
            }
        }
        Err(e) => {
            eprintln!("Error: {e}");
            std::process::exit(1);
        }
    }
}

pub fn notes_set(project_name: &str, ws_name: &str, content: &str, host: Option<&str>) {
    let content = if content == "-" {
        use std::io::Read;
        let mut buf = String::new();
        std::io::stdin()
            .read_to_string(&mut buf)
            .unwrap_or_else(|e| {
                eprintln!("Error reading stdin: {e}");
                std::process::exit(1);
            });
        buf
    } else {
        content.to_string()
    };

    let mut client = daemon_client::connect_to_hub_or_exit();

    let mut params = json!({"project": project_name, "name": ws_name, "content": content});
    if let Some(h) = host {
        params["host"] = json!(h);
    }

    match client.request("workstream.set-notes", params) {
        Ok(_) => println!("Notes updated for workstream '{ws_name}'"),
        Err(e) => {
            eprintln!("Error: {e}");
            std::process::exit(1);
        }
    }
}

pub fn delete(project_name: &str, ws_name: &str, host: Option<&str>) {
    let mut client = daemon_client::connect_to_hub_or_exit();

    let mut params = json!({"project": project_name, "name": ws_name});
    if let Some(h) = host {
        params["host"] = json!(h);
    }

    match client.request("workstream.delete", params) {
        Ok(_) => println!("Deleted workstream '{ws_name}'"),
        Err(e) => {
            eprintln!("Error: {e}");
            std::process::exit(1);
        }
    }
}