# shellcheck shell=bash
# Shared lazy-install logic sourced by each agent wrapper.

# ── Strip wrapper directory from PATH ────────────────────────────
_path_without_wrappers() {
    local _wdir="$HOME/.devcage/bin"
    local _p=":${PATH}:"
    _p="${_p//":${_wdir}:"/:}"
    _p="${_p#:}"; _p="${_p%:}"
    printf '%s' "$_p"
}

# ── Pick up PATH additions from shell profiles after install ─────
# Some installers (e.g. Claude's standalone binary) add directories
# to .bashrc/.profile rather than installing into a standard PATH
# directory.  This scans profile files for PATH= lines and merges
# any new directories into the current PATH so _exec_real can find
# the freshly installed binary.
_refresh_path_from_profiles() {
    local _prof _line _rhs _dir
    for _prof in "$HOME/.bashrc" "$HOME/.profile" "$HOME/.bash_profile"; do
        [ -f "$_prof" ] || continue
        while IFS= read -r _line; do
            # Match lines setting PATH (export PATH=… or PATH=…), not MANPATH etc.
            [[ "$_line" =~ (^|[[:space:]])PATH= || "$_line" =~ ^export[[:space:]]+PATH= ]] || continue
            # Strip everything up to and including PATH=
            _rhs="${_line#*PATH=}"
            # Strip optional leading quote
            _rhs="${_rhs#\"}"
            _rhs="${_rhs#\'}"
            # Strip $PATH / ${PATH} reference and everything after it
            _rhs="${_rhs%%\$PATH*}"
            _rhs="${_rhs%%\$\{PATH\}*}"
            # Strip trailing quote, semicolon, colon
            _rhs="${_rhs%\"}"
            _rhs="${_rhs%\'}"
            _rhs="${_rhs%;}"
            _rhs="${_rhs%:}"
            [ "$_rhs" = "" ] && continue
            # Split on : and add each missing directory to PATH
            local -a _dirs; IFS=: read -ra _dirs <<< "$_rhs"
            for _dir in "${_dirs[@]}"; do
                # Expand $HOME / ${HOME} / ~ references
                _dir="${_dir//\$HOME/$HOME}"
                _dir="${_dir//\$\{HOME\}/$HOME}"
                _dir="${_dir/#\~/$HOME}"
                _dir="${_dir%/}"
                [ "$_dir" != "" ] && [ -d "$_dir" ] && [[ ":${PATH}:" != *":${_dir}:"* ]] && {
                    export PATH="${_dir}:${PATH}"
                }
            done
        done < "$_prof"
    done
}

# ── Resolve real binary and exec ─────────────────────────────────
_exec_real() {
    local _wrapper="$1" _bin="$2"; shift 2
    local _real
    _real="$(PATH="$(_path_without_wrappers)" command -v "$_bin" 2>/dev/null || true)"
    if [ "$_real" = "" ] || [ ! -x "$_real" ]; then
        echo "Error: ${_bin} not found after install — wrapper kept for retry" >&2
        return 1
    fi
    # Create a symlink in ~/.local/bin/ when the real binary lives outside
    # standard PATH dirs, so it remains findable across container restarts.
    # Only do this for pure install shims (wrapper == binary name); alias
    # wrappers (e.g. claude-yolo → claude) skip this.
    if [ "$_wrapper" = "$_bin" ]; then
        local _real_dir
        _real_dir="$(dirname "$_real")"
        if [ "$_real_dir" != "$HOME/.local/bin" ] \
            && [ "$_real_dir" != "$HOME/.npm-global/bin" ] \
            && [ ! -e "$HOME/.local/bin/$_bin" ]; then
            mkdir -p "$HOME/.local/bin" 2>/dev/null || true
            ln -sf "$_real" "$HOME/.local/bin/$_bin" 2>/dev/null || true
        fi
    fi
    # NOTE: The wrapper is intentionally kept in place.  Removing it
    # breaks the parent shell's command hash table — bash caches the
    # wrapper path and returns "No such file or directory" on the next
    # invocation.  The wrapper is a fast pass-through (~30 ms) once the
    # real binary is installed.
    exec "$_real" "$@"
}

ensure_installed() {
    local binary_name="$1" install_cmd="$2"
    if ! command -v "$binary_name" >/dev/null 2>&1 || [ "$(command -v "$binary_name")" = "$HOME/.devcage/bin/$binary_name" ]; then
        # Pick up PATH additions from a previous install session (the
        # installer may have written to .bashrc which hasn't been
        # re-sourced in this shell).
        _refresh_path_from_profiles
        # Check if the real binary exists (not just our wrapper)
        local real_path
        real_path="$(PATH="$(_path_without_wrappers)" command -v "$binary_name" 2>/dev/null || true)"
        if [ "$real_path" = "" ] || [ ! -x "$real_path" ]; then
            echo "Installing $binary_name..." >&2
            # Download-then-execute: avoids piping curl directly into bash.
            # The install command may be "curl ... | bash" for first-party installers
            # (e.g. claude.ai, sdkman.io) — rewrite to download first, then execute.
            local _dl_script
            _dl_script="$(mktemp "${TMPDIR:-/tmp}/devcage-install-XXXXXXXX.sh")" || { echo "Error: mktemp failed" >&2; return 1; }
            # shellcheck disable=SC2064
            trap "rm -f '$_dl_script'" RETURN
            if [[ "$install_cmd" =~ curl[[:space:]].*\|[[:space:]]*bash ]]; then
                # Extract curl command (everything before the pipe)
                local _curl_part="${install_cmd%%|*}"
                # Download to temp file, then execute (array invocation avoids eval)
                local _curl_args
                read -ra _curl_args <<< "$_curl_part"
                "${_curl_args[@]}" -o "$_dl_script" || { echo "Error: download failed for ${binary_name}" >&2; rm -f "$_dl_script"; return 1; }
                if ! head -1 "$_dl_script" | grep -q '^#!'; then
                    echo "Error: downloaded installer for ${binary_name} does not look like a shell script" >&2
                    rm -f "$_dl_script"; return 1
                fi
                bash "$_dl_script"
            else
                bash -c "$install_cmd"
            fi
            # Pick up PATH additions the installer may have written to
            # shell profile files (e.g. .bashrc).  Without this, the
            # current session won't see the new binary location.
            _refresh_path_from_profiles
        fi
    fi
}
