partiri-cli 0.2.0

Partiri CLI — Deploy and manage services on Partiri Cloud
use inquire::Confirm;

use crate::client::ApiClient;
use crate::config::{PartiriConfig, CONFIG_FILE};
use crate::error::{CliError, Result};
use crate::modules::init::{
    prompt_for_pod, prompt_for_project, prompt_for_region, prompt_for_workspace,
};
use crate::output::{ctx, print_success};

pub struct LinkArgs {
    pub workspace: Option<String>,
    pub project: Option<String>,
    pub region: Option<String>,
    pub pod: Option<String>,
    pub token: Option<String>,
    pub clear_token: bool,
}

impl LinkArgs {
    fn any_flag(&self) -> bool {
        self.workspace.is_some()
            || self.project.is_some()
            || self.region.is_some()
            || self.pod.is_some()
            || self.token.is_some()
            || self.clear_token
    }
}

pub fn run(client: &ApiClient, mut config: PartiriConfig, args: LinkArgs) -> Result<()> {
    if args.any_flag() {
        return run_with_flags(config, args);
    }
    run_interactive(client, &mut config)
}

fn run_with_flags(mut config: PartiriConfig, args: LinkArgs) -> Result<()> {
    if args.workspace.is_some() && args.project.is_none() {
        return Err(
            "--workspace requires --project (projects don't carry across workspaces).".into(),
        );
    }
    if args.region.is_some() && args.pod.is_none() {
        return Err(
            "--region requires --pod (pods are scoped to their region's workspace).".into(),
        );
    }

    let mut changed = false;
    if let Some(w) = args.workspace {
        config.fk_workspace = w;
        changed = true;
    }
    if let Some(p) = args.project {
        config.fk_project = p;
        changed = true;
    }
    if let Some(r) = args.region {
        config.service.fk_region = r;
        changed = true;
    }
    if let Some(p) = args.pod {
        config.service.fk_pod = p;
        changed = true;
    }
    if let Some(t) = args.token {
        config.service.fk_service_secret = Some(t);
        changed = true;
    } else if args.clear_token {
        config.service.fk_service_secret = None;
        changed = true;
    }

    if !changed {
        println!("No changes.");
        return Ok(());
    }

    config.save()?;
    print_success(&format!("{} updated.", CONFIG_FILE));
    Ok(())
}

fn run_interactive(client: &ApiClient, config: &mut PartiriConfig) -> Result<()> {
    if ctx().no_input {
        return Err(Box::new(
            CliError::new(
                "validation",
                "service link in non-interactive mode requires at least one of --workspace, --project, --region, --pod, --token, or --clear-token.",
            )
            .with_hint(
                "Pair --workspace with --project, and --region with --pod. Run 'partiri -j llm context' to find UUIDs.",
            )
            .enriched(),
        ));
    }

    let mut changed = false;
    let mut workspace_changed = false;
    let mut region_changed = false;

    // Step 1 — Workspace
    let update_ws = Confirm::new("Update workspace?")
        .with_default(false)
        .prompt()
        .map_err(|_| "Cancelled.")?;
    if update_ws {
        config.fk_workspace = prompt_for_workspace(Some(client))?;
        workspace_changed = true;
        changed = true;
    }

    // Step 2 — Project (forced when workspace changed)
    let update_proj = if workspace_changed {
        println!("  Workspace changed — project must be re-selected.");
        true
    } else {
        Confirm::new("Update project?")
            .with_default(false)
            .prompt()
            .map_err(|_| "Cancelled.")?
    };
    if update_proj {
        config.fk_project = prompt_for_project(Some(client), &config.fk_workspace)?;
        changed = true;
    }

    // Step 3 — Region
    let update_region = Confirm::new("Update region?")
        .with_default(false)
        .prompt()
        .map_err(|_| "Cancelled.")?;
    if update_region {
        config.service.fk_region = prompt_for_region(Some(client), &config.fk_workspace)?;
        region_changed = true;
        changed = true;
    }

    // Step 4 — Pod (forced when region changed)
    let update_pod = if region_changed {
        println!("  Region changed — pod must be re-selected.");
        true
    } else {
        Confirm::new("Update pod?")
            .with_default(false)
            .prompt()
            .map_err(|_| "Cancelled.")?
    };
    if update_pod {
        config.service.fk_pod = prompt_for_pod(Some(client), &config.fk_workspace)?;
        changed = true;
    }

    if !changed {
        println!("No changes.");
        return Ok(());
    }

    config.save()?;
    print_success(&format!("{} updated.", CONFIG_FILE));
    Ok(())
}