//! Ruby SCIP indexer install path: download standalone binary from
//! sourcegraph/scip-ruby GitHub releases.
//!
//! Why not `gem install`: the gem ships a stub that REQUIRES `bundle exec`
//! AND requires scip-ruby to be in the target project's Gemfile. That breaks
//! `ckg index` for any Ruby repo that doesn't already depend on scip-ruby.
//! The standalone binary published on GitHub releases has no such constraint
//! and is the path Sourcegraph documents for this case.

use std::path::Path;
use std::process::Command;

use anyhow::{Context, Result, bail};
use ckg_fs::has_command;

use super::bootstrap::BootstrapEnv;
use super::installer::{InstallCtx, Installer};
use super::{SCIP_RUBY_VERSION, assert_online};

pub(super) struct RubyInstaller;

impl Installer for RubyInstaller {
    fn name(&self) -> &'static str {
        "ruby"
    }
    fn install(&self, ctx: &InstallCtx<'_>, _env: &dyn BootstrapEnv) -> Result<()> {
        install_scip_ruby(ctx)
    }
}

fn install_scip_ruby(ctx: &InstallCtx<'_>) -> Result<()> {
    if has_command("scip-ruby") {
        eprintln!("scip-ruby: already on $PATH — skipping");
        return Ok(());
    }
    let bin_dir: &Path = ctx.bin_dir;
    let dest = bin_dir.join("scip-ruby");

    let asset = release_asset_name()?;
    let url = format!(
        "https://github.com/sourcegraph/scip-ruby/releases/download/scip-ruby-v{SCIP_RUBY_VERSION}/{asset}"
    );

    assert_online("download scip-ruby release binary")?;
    eprintln!("scip-ruby: curl -fsSL {url} -o {}", dest.display());

    std::fs::create_dir_all(bin_dir).with_context(|| format!("mkdir {}", bin_dir.display()))?;
    let status = Command::new("curl")
        .args(["-fsSL", "--retry", "3", "--retry-delay", "2", "-o"])
        .arg(&dest)
        .arg(&url)
        .status()
        .with_context(|| "spawning curl")?;
    if !status.success() {
        let _ = std::fs::remove_file(&dest);
        bail!("curl exited {status} fetching {url}");
    }

    #[cfg(unix)]
    {
        use std::os::unix::fs::PermissionsExt;
        let mut perms = std::fs::metadata(&dest)?.permissions();
        perms.set_mode(0o755);
        std::fs::set_permissions(&dest, perms)
            .with_context(|| format!("chmod +x {}", dest.display()))?;
    }

    eprintln!("scip-ruby: installed → {}", dest.display());
    Ok(())
}

/// Map this host to the GitHub release asset name. scip-ruby publishes
/// `scip-ruby-{arch}-{os}` for arm64-darwin and x86_64-linux only (per
/// scip-ruby v0.4.7 release).
fn release_asset_name() -> Result<&'static str> {
    let asset = match (std::env::consts::ARCH, std::env::consts::OS) {
        ("aarch64", "macos") | ("arm64", "macos") => "scip-ruby-arm64-darwin",
        ("x86_64", "linux") => "scip-ruby-x86_64-linux",
        (arch, os) => bail!(
            "scip-ruby has no published binary for {arch}-{os}. Supported: \
             arm64-darwin, x86_64-linux. Build from source: \
             https://github.com/sourcegraph/scip-ruby"
        ),
    };
    Ok(asset)
}
