#!/bin/sh
set -eu

MIN_RUST="1.85.0"
LIOS_CRATE_VERSION="${LIOS_CRATE_VERSION:-0.1.76}"
CARGO_BUILD_JOBS="${CARGO_BUILD_JOBS:-2}"
export CARGO_BUILD_JOBS

say() {
    printf '%s\n' "lios: $*"
}

die() {
    printf '%s\n' "lios: error: $*" >&2
    exit 1
}

version_at_least() {
    awk -v required="$1" -v actual="$2" 'BEGIN {
        split(required, want, ".")
        split(actual, have, ".")
        for (part = 1; part <= 3; part++) {
            if ((have[part] + 0) > (want[part] + 0)) exit 0
            if ((have[part] + 0) < (want[part] + 0)) exit 1
        }
        exit 0
    }'
}

check_dependencies() {
    command -v pkg-config >/dev/null 2>&1 || return 1
    command -v cc >/dev/null 2>&1 || \
        command -v gcc >/dev/null 2>&1 || \
        command -v clang >/dev/null 2>&1 || return 1
    pkg-config --atleast-version=4.0 gtk4 || return 1
    pkg-config --atleast-version=0.70 vte-2.91-gtk4 || return 1
}

check_rust() {
    command -v rustc >/dev/null 2>&1 || return 1
    command -v cargo >/dev/null 2>&1 || return 1
    rust_version=$(rustc --version | cut -d ' ' -f 2)
    version_at_least "$MIN_RUST" "$rust_version"
}

report() {
    say "architecture: $(uname -m)"
    if command -v pkg-config >/dev/null 2>&1; then
        gtk_version=$(pkg-config --modversion gtk4 2>/dev/null || printf 'missing')
        vte_version=$(pkg-config --modversion vte-2.91-gtk4 2>/dev/null || printf 'missing')
    else
        gtk_version="missing"
        vte_version="missing"
    fi
    if command -v rustc >/dev/null 2>&1; then
        rust_version=$(rustc --version | cut -d ' ' -f 2)
    else
        rust_version="missing"
    fi
    if command -v cargo >/dev/null 2>&1; then
        cargo_version=$(cargo --version | cut -d ' ' -f 2)
    else
        cargo_version="missing"
    fi
    if command -v cc >/dev/null 2>&1; then
        linker="cc"
    elif command -v gcc >/dev/null 2>&1; then
        linker="gcc"
    elif command -v clang >/dev/null 2>&1; then
        linker="clang"
    else
        linker="missing"
    fi
    say "GTK4: ${gtk_version} (minimum 4.0)"
    say "VTE GTK4: ${vte_version} (minimum 0.70)"
    say "Rust: ${rust_version} (minimum ${MIN_RUST})"
    say "Cargo: ${cargo_version}"
    say "native linker: ${linker}"
}

launch=false
case "${1:-}" in
    --check)
        report
        check_dependencies || exit 1
        check_rust || exit 1
        exit 0
        ;;
    --launch)
        launch=true
        shift
        ;;
    --help|-h)
        printf '%s\n' \
            "Usage: sh install-jetson.sh [--check | --launch [ARGS...]]" \
            "" \
            "Installs Lios and its GTK4/VTE build dependencies with common Linux" \
            "package managers. Native libraries come from the distribution so they" \
            "continue receiving its ABI-compatible security updates."
        exit 0
        ;;
    "") ;;
    *) die "unknown option: $1" ;;
esac

install_dependencies() {
    if [ "$(id -u)" -eq 0 ]; then
        SUDO=""
    elif command -v sudo >/dev/null 2>&1; then
        SUDO="sudo"
    elif command -v doas >/dev/null 2>&1; then
        SUDO="doas"
    else
        die "sudo is required to install system dependencies"
    fi

    say "installing distribution-managed GTK4, VTE GTK4, and Rust build prerequisites"
    if command -v apt-get >/dev/null 2>&1; then
        $SUDO apt-get update
        $SUDO apt-get install -y \
            build-essential ca-certificates curl libgtk-4-dev pkg-config
        if apt-cache show libvte-2.91-gtk4-dev >/dev/null 2>&1; then
            $SUDO apt-get install -y libvte-2.91-gtk4-dev
        fi
    elif command -v dnf >/dev/null 2>&1; then
        $SUDO dnf install -y \
            gcc gcc-c++ make ca-certificates curl gtk4-devel pkgconf-pkg-config
        if dnf -q info vte291-gtk4-devel >/dev/null 2>&1; then
            $SUDO dnf install -y vte291-gtk4-devel
        fi
    elif command -v pacman >/dev/null 2>&1; then
        $SUDO pacman -S --needed --noconfirm \
            base-devel ca-certificates curl gtk4 pkgconf vte4
    elif command -v zypper >/dev/null 2>&1; then
        $SUDO zypper --non-interactive install \
            gcc gcc-c++ make ca-certificates curl gtk4-devel pkg-config
        $SUDO zypper --non-interactive install vte-2_91-gtk4-devel || true
    elif command -v apk >/dev/null 2>&1; then
        $SUDO apk add --no-cache \
            build-base ca-certificates curl gtk4.0-dev pkgconf vte3-dev
    elif command -v xbps-install >/dev/null 2>&1; then
        $SUDO xbps-install -Sy \
            base-devel ca-certificates curl gtk4-devel pkg-config vte3-gtk4-devel
    else
        die "supported package manager not found (apt, dnf, pacman, zypper, apk, or xbps required)"
    fi

    pkg-config --atleast-version=4.0 gtk4 2>/dev/null || \
        die "the distribution did not provide GTK4 4.0 or newer"
    pkg-config --atleast-version=0.70 vte-2.91-gtk4 2>/dev/null || \
        die "the distribution did not provide VTE GTK4 0.70 or newer; use a newer distribution or a maintained portable Lios package"
    say "using distribution VTE GTK4 $(pkg-config --modversion vte-2.91-gtk4)"
}

if check_dependencies; then
    say "using installed GTK4 $(pkg-config --modversion gtk4) and VTE GTK4 $(pkg-config --modversion vte-2.91-gtk4)"
else
    install_dependencies
    check_dependencies || {
        report
        die "GTK4 or VTE GTK4 did not meet the required version after installation"
    }
fi

rust_version=$(rustc --version 2>/dev/null | cut -d ' ' -f 2 || true)
if [ -z "$rust_version" ] || ! version_at_least "$MIN_RUST" "$rust_version"; then
    say "installing a current Rust toolchain with rustup"
    if command -v rustup >/dev/null 2>&1; then
        rustup toolchain install stable --profile minimal
        # Select stable only for this install; do not rewrite the user's global
        # rustup default from an application bootstrapper.
        RUSTUP_TOOLCHAIN=stable
        export RUSTUP_TOOLCHAIN
    else
        command -v curl >/dev/null 2>&1 || \
            die "curl is required to install Rust because rustup is unavailable"
        curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain stable
    fi
fi

if [ -f "$HOME/.cargo/env" ]; then
    # shellcheck disable=SC1091
    . "$HOME/.cargo/env"
fi
command -v cargo >/dev/null 2>&1 || die "cargo is unavailable after Rust installation"

report
say "installing Lios"
if [ -n "${LIOS_INSTALL_ROOT:-}" ]; then
    cargo install --locked --force --version "=${LIOS_CRATE_VERSION}" --features native --root "$LIOS_INSTALL_ROOT" lios
    lios_bin="$LIOS_INSTALL_ROOT/bin/lios"
else
    cargo install --locked --force --version "=${LIOS_CRATE_VERSION}" --features native lios
    lios_bin="${CARGO_HOME:-$HOME/.cargo}/bin/lios"
fi

[ -x "$lios_bin" ] || lios_bin=$(command -v lios || true)
[ -n "$lios_bin" ] || die "Lios installed but its binary was not found"
installed_version=$("$lios_bin" --version 2>/dev/null || true)
[ "$installed_version" = "lios ${LIOS_CRATE_VERSION}" ] || \
    die "installed binary failed native version verification (expected lios ${LIOS_CRATE_VERSION})"
"$lios_bin" --install

say "installation complete; launch Lios from the app menu or run $lios_bin"
if [ "$launch" = true ]; then
    exec "$lios_bin" "$@"
fi
