#!/bin/sh
set -eu

fail() {
    printf 'RustClamp installer: %s\n' "$1" >&2
    exit 1
}

os=$(uname -s)
arch=$(uname -m)
case "$os/$arch" in
    Linux/x86_64|Linux/aarch64|Linux/arm64|Darwin/x86_64|Darwin/arm64) ;;
    *) fail "unsupported platform: $os/$arch (supported: Linux and macOS on x86_64 or ARM64)." ;;
esac
printf 'Detected %s on %s.\n' "$os" "$arch"

command -v curl >/dev/null 2>&1 || fail 'curl is required to download RustClamp and Rust.'
command -v tar >/dev/null 2>&1 || fail 'tar is required to unpack RustClamp source.'
[ -n "${HOME:-}" ] || fail 'HOME must be set.'
cargo_home=${CARGO_HOME:-$HOME/.cargo}

case ":${PATH}:" in
    *":$cargo_home/bin:"*) cargo_bin_was_in_path=yes ;;
    *) cargo_bin_was_in_path=no; PATH="$cargo_home/bin:$PATH"; export PATH ;;
esac

if ! command -v cargo >/dev/null 2>&1 || ! command -v rustup >/dev/null 2>&1; then
    printf 'Rust toolchain not found; installing Rust with rustup…\n'
    curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal
    [ ! -f "$cargo_home/env" ] || . "$cargo_home/env"
    PATH="$cargo_home/bin:$PATH"
    export PATH
fi

command -v cargo >/dev/null 2>&1 || fail 'Cargo installation did not complete; see https://rust-lang.org/tools/install/.'
if ! command -v cc >/dev/null 2>&1 && ! command -v clang >/dev/null 2>&1; then
    case "$os" in
        Linux)
            command -v sudo >/dev/null 2>&1 || fail 'build tools are missing and sudo is unavailable; install your distribution C compiler and linker, then rerun.'
            printf 'Installing native build tools with the detected package manager…\n'
            if command -v pacman >/dev/null 2>&1; then
                sudo pacman -S --needed --noconfirm base-devel
            elif command -v apt-get >/dev/null 2>&1; then
                sudo apt-get update
                sudo apt-get install -y build-essential
            elif command -v dnf >/dev/null 2>&1; then
                sudo dnf install -y gcc gcc-c++ make
            elif command -v apk >/dev/null 2>&1; then
                sudo apk add build-base
            elif command -v zypper >/dev/null 2>&1; then
                sudo zypper --non-interactive install gcc gcc-c++ make
            else
                fail 'no supported Linux package manager found; install your C compiler and linker, then rerun.'
            fi
            command -v cc >/dev/null 2>&1 || command -v clang >/dev/null 2>&1 || fail 'build tools installed, but no C compiler was found; check your distribution setup.'
            ;;
        Darwin)
            xcode-select --install || true
            fail 'finish the Xcode Command Line Tools installation, then rerun this command.'
            ;;
    esac
fi

work=$(mktemp -d "${TMPDIR:-/tmp}/rustclamp-install.XXXXXX") || fail 'cannot create a temporary directory.'
trap 'rm -rf "$work"' EXIT HUP INT TERM

case "$os/$arch" in
    Linux/x86_64) target=x86_64-unknown-linux-gnu ;;
    Darwin/x86_64) target=x86_64-apple-darwin ;;
    Darwin/arm64) target=aarch64-apple-darwin ;;
    *) target= ;;
esac
if command -v sha256sum >/dev/null 2>&1; then sha256='sha256sum'; else sha256='shasum -a 256'; fi

# Prefer the latest release binary; build pinned source when none exists for this platform.
installed=no
tag=$(curl --proto '=https' --tlsv1.2 -fsSLo /dev/null -w '%{url_effective}' https://github.com/rustclamp/rustclamp/releases/latest 2>/dev/null || true)
tag=${tag##*/}
if [ -n "$target" ] && [ "${tag#clamp-v}" != "$tag" ]; then
    name="clamp-${tag#clamp-v}-$target.tar.gz"
    printf 'Downloading clamp %s for %s…\n' "${tag#clamp-v}" "$target"
    if curl --proto '=https' --tlsv1.2 -fsSL -o "$work/$name" "https://github.com/rustclamp/rustclamp/releases/download/$tag/$name" \
        && curl --proto '=https' --tlsv1.2 -fsSL -o "$work/$name.sha256" "https://github.com/rustclamp/rustclamp/releases/download/$tag/$name.sha256"; then
        (cd "$work" && $sha256 -c "$name.sha256" >/dev/null) || fail "checksum mismatch for $name."
        tar -xzf "$work/$name" -C "$work"
        mkdir -p "$cargo_home/bin"
        # Copy beside, then rename: cp over a running clamp (self-update) fails with "Text file busy".
        cp "$work/${name%.tar.gz}/clamp" "$cargo_home/bin/clamp.new"
        chmod 755 "$cargo_home/bin/clamp.new"
        mv -f "$cargo_home/bin/clamp.new" "$cargo_home/bin/clamp"
        installed=yes
    else
        printf 'Release download failed; building from source instead.\n'
    fi
fi

if [ "$installed" = no ]; then
    # Pinned to the commits clamp-v0.5.0 was released from; tags and branches can move, SHAs can't.
    # ponytail: pins are bumped by hand on each clamp release.
    printf 'Fetching RustClamp source (clamp 0.5.0)…\n'
    for repo_sha in \
        core:6c0fc94abc78df7b7279b4c2a062324aa73fc5a8 \
        kernel:18661928eb20d1c81fa2a4fe067ff96148d3702e \
        rustclamp:52b8b46753ba9d09ec7e4049d165a9fa9576da50; do
        repo=${repo_sha%%:*}
        sha=${repo_sha#*:}
        mkdir "$work/$repo"
        curl --proto '=https' --tlsv1.2 -fsSL "https://codeload.github.com/rustclamp/$repo/tar.gz/$sha" \
            | tar -xz --strip-components=1 -C "$work/$repo"
    done

    printf 'Building and installing clamp globally for this user…\n'
    (cd "$work/rustclamp" && cargo install --locked --path tooling --force)
fi

printf '\nClamp is installed in %s/bin/clamp.\n' "$cargo_home"
if [ "$cargo_bin_was_in_path" = yes ]; then
    printf 'Run `clamp` to open the welcome menu.\n'
else
    shell_name=${SHELL:-}
    case "${shell_name##*/}" in
            zsh)
                profile=$HOME/.zshrc
                path_line='export PATH="$HOME/.cargo/bin:$PATH"'
                reload='source "$HOME/.zshrc"; rehash'
                ;;
            bash)
                profile=$HOME/.bashrc
                [ ! -f "$HOME/.bash_profile" ] || profile=$HOME/.bash_profile
                path_line='export PATH="$HOME/.cargo/bin:$PATH"'
                reload=". $profile"
                ;;
            fish)
                profile=${XDG_CONFIG_HOME:-$HOME/.config}/fish/config.fish
                path_line='fish_add_path "$HOME/.cargo/bin"'
                reload='fish_add_path "$HOME/.cargo/bin"'
                ;;
            *)
                if [ -f "$HOME/.zshrc" ]; then
                    profile=$HOME/.zshrc
                    path_line='export PATH="$HOME/.cargo/bin:$PATH"'
                    reload='source "$HOME/.zshrc"; rehash'
                elif [ -f "$HOME/.bashrc" ]; then
                    profile=$HOME/.bashrc
                    path_line='export PATH="$HOME/.cargo/bin:$PATH"'
                    reload='. "$HOME/.bashrc"'
                else
                    profile=
                fi
                ;;
    esac
    if [ "$cargo_home" = "$HOME/.cargo" ] && [ -n "$profile" ]; then
        mkdir -p "$(dirname "$profile")"
        if ! grep -Fqx "$path_line" "$profile" 2>/dev/null; then
            printf '\n# RustClamp command line tools\n%s\n' "$path_line" >> "$profile"
        fi
        printf 'Configured global PATH in %s. Run `%s` now, or open a new terminal.\n' "$profile" "$reload"
    else
        printf 'Add %s/bin to your shell PATH to run clamp.\n' "$cargo_home"
    fi
fi
