use crate::{error::SkipStep, execution_context::ExecutionContext, terminal::print_separator, utils};
use anyhow::Result;

fn prepare_async_ssh_command(args: &mut Vec<&str>) {
    args.insert(0, "ssh");
    args.push("--keep");
}

pub fn ssh_step(ctx: &ExecutionContext, hostname: &str) -> Result<()> {
    let ssh = utils::require("ssh")?;

    let topgrade = ctx.config().remote_topgrade_path();
    let mut args = vec!["-t", hostname];

    if let Some(ssh_arguments) = ctx.config().ssh_arguments() {
        args.extend(ssh_arguments.split_whitespace());
    }

    let env = format!("TOPGRADE_PREFIX={}", hostname);
    args.extend(&["env", &env, topgrade]);

    if ctx.config().yes() {
        args.push("-y");
    }

    if ctx.config().run_in_tmux() && !ctx.run_type().dry() {
        #[cfg(unix)]
        {
            prepare_async_ssh_command(&mut args);
            crate::tmux::run_command(ctx, &args.join(" "))?;
            Err(SkipStep(String::from("Remote Topgrade launched in Tmux")).into())
        }

        #[cfg(not(unix))]
        unreachable!("Tmux execution is only implemented in Unix");
    } else if ctx.config().open_remotes_in_new_terminal() && !ctx.run_type().dry() && cfg!(windows) {
        prepare_async_ssh_command(&mut args);
        ctx.run_type().execute("wt").args(&args).spawn()?;
        Err(SkipStep(String::from("Remote Topgrade launched in an external terminal")).into())
    } else {
        let mut args = vec!["-t", hostname];

        if let Some(ssh_arguments) = ctx.config().ssh_arguments() {
            args.extend(ssh_arguments.split_whitespace());
        }

        let env = format!("TOPGRADE_PREFIX={}", hostname);
        args.extend(&["env", &env, topgrade]);

        if ctx.config().yes() {
            args.push("-y");
        }

        print_separator(format!("Remote ({})", hostname));
        println!("Connecting to {}...", hostname);

        ctx.run_type().execute(&ssh).args(&args).check_run()
    }
}
