#!/usr/bin/env bash

# Qwen Code Installation Script
# Installs Qwen Code from a standalone archive when available, with npm fallback.
# This script intentionally does not install Node.js or change npm config.
#
# Usage:
#   install-qwen-standalone.sh --source [github|npm|internal|local-build]
#   install-qwen-standalone.sh --method [detect|standalone|npm]

if [ -z "${BASH_VERSION}" ] && [ -z "${__QWEN_INSTALL_REEXEC:-}" ]; then
    if command -v bash >/dev/null 2>&1; then
        if [ -f "${0}" ]; then
            export __QWEN_INSTALL_REEXEC=1
            exec bash -- "${0}" "$@"
        fi

        echo "Error: This script requires bash. Run the installer with: curl ... | bash"
        exit 1
    fi

    echo "Error: This script requires bash. Please install bash first."
    exit 1
fi

set -eo pipefail

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
MUTED='\033[0;2m'
NC='\033[0m'
BRAND_ORANGE='\033[38;5;214m'

supports_truecolor() {
    [[ "${COLORTERM:-}" == "truecolor" || "${COLORTERM:-}" == "24bit" ]]
}

if supports_truecolor; then
    BRAND_BLUE='\033[38;2;71;150;228m'
    BRAND_PURPLE='\033[38;2;132;122;206m'
else
    BRAND_BLUE='\033[38;5;68m'
    BRAND_PURPLE='\033[38;5;140m'
fi

log_info() {
    printf '%bINFO:%b %s\n' "${BLUE}" "${NC}" "$1"
}

log_success() {
    printf '%bSUCCESS:%b %s\n' "${GREEN}" "${NC}" "$1"
}

log_warning() {
    printf '%bWARNING:%b %s\n' "${YELLOW}" "${NC}" "$1"
}

log_error() {
    printf '%bERROR:%b %s\n' "${RED}" "${NC}" "$1" >&2
}

command_exists() {
    command -v "$1" >/dev/null 2>&1
}

is_terminal() {
    [ -t 2 ]
}

print_progress() {
    local bytes="$1"
    local length="$2"
    [ "$length" -gt 0 ] || return 0
    local width=50
    local percent=$(( bytes * 100 / length ))
    [ "$percent" -gt 100 ] && percent=100
    local on=$(( percent * width / 100 ))
    local off=$(( width - on ))
    local filled=$(printf "%*s" "$on" "")
    filled=${filled// /■}
    local empty=$(printf "%*s" "$off" "")
    empty=${empty// /･}
    printf "\r${BRAND_ORANGE}%s%s %3d%%${NC}" "$filled" "$empty" "$percent" >&2
}

finish_progress() {
    print_progress 1 1
    echo "" >&2
}

TEMP_DIRS=()
ACTIVE_DOWNLOAD_PID=""
PATH_UPDATE_APPLIED=0
# PATH as inherited from the invoking shell. The script later prepends the
# install dir to its own PATH, but that never propagates to the parent shell
# (a piped `curl | bash` runs in a child process), so we keep the original
# value to decide whether the user must reload their shell rc file.
ORIGINAL_PATH="${PATH:-}"

cleanup_temp_dirs() {
    local temp_dir
    for temp_dir in "${TEMP_DIRS[@]}"; do
        if [[ -n "${temp_dir}" ]]; then
            rm -rf "${temp_dir}"
        fi
    done
}

register_temp_dir() {
    local temp_dir="$1"
    TEMP_DIRS+=("${temp_dir}")
}

restore_cursor() {
    printf "\033[?25h"
}

kill_active_download() {
    if [[ -n "${ACTIVE_DOWNLOAD_PID}" ]]; then
        kill "${ACTIVE_DOWNLOAD_PID}" 2>/dev/null || true
        ACTIVE_DOWNLOAD_PID=""
    fi
}

shell_quote() {
    printf "'%s'" "$(printf '%s' "$1" | sed "s/'/'\\\\''/g")"
}

display_install_version() {
    if [[ "${VERSION}" == "latest" ]]; then
        echo "latest"
        return 0
    fi

    echo "${VERSION#v}"
}

trap cleanup_temp_dirs EXIT
trap 'restore_cursor >&2; kill_active_download; cleanup_temp_dirs; exit 130' INT
trap 'restore_cursor >&2; kill_active_download; cleanup_temp_dirs; exit 143' TERM

print_usage() {
    cat <<EOF
Qwen Code Installer

Usage: $0 [OPTIONS]

Options:
  --method METHOD      Install method: detect, standalone, or npm (default: detect)
  --mirror MIRROR      Mirror: auto, github, or aliyun (default: auto)
  --base-url URL       Override standalone archive base URL
  --archive PATH       Install from a local standalone archive
  --version VERSION    Release version (default: latest)
  --registry URL       npm registry (default: https://registry.npmmirror.com)
  --no-modify-path     Do not modify shell rc file
  -s, --source SOURCE  Record installation source
  -h, --help           Show this help message

Example:
  curl -fsSL https://qwen-code-assets.oss-cn-hangzhou.aliyuncs.com/installation/install-qwen-standalone.sh | bash
EOF
}

SOURCE="unknown"
METHOD="${QWEN_INSTALL_METHOD:-}"
MIRROR="${QWEN_INSTALL_MIRROR:-auto}"
BASE_URL="${QWEN_INSTALL_BASE_URL:-}"
ARCHIVE_PATH="${QWEN_INSTALL_ARCHIVE:-}"
VERSION="${QWEN_INSTALL_VERSION:-0.19.3}"
NO_MODIFY_PATH="${QWEN_NO_MODIFY_PATH:-0}"
NPM_REGISTRY="${QWEN_NPM_REGISTRY:-https://registry.npmmirror.com}"
INSTALL_ROOT="${QWEN_INSTALL_ROOT:-${HOME:-}/.local}"
if [[ -n "${QWEN_INSTALL_LIB_DIR:-}" ]]; then
    INSTALL_LIB_DIR="${QWEN_INSTALL_LIB_DIR}"
    INSTALL_LIB_PARENT="$(dirname "${INSTALL_LIB_DIR}")"
else
    INSTALL_LIB_PARENT="${QWEN_INSTALL_LIB_PARENT:-${INSTALL_ROOT}/lib}"
    INSTALL_LIB_DIR="${INSTALL_LIB_PARENT}/qwen-code"
fi
INSTALL_BIN_DIR="${QWEN_INSTALL_BIN_DIR:-${INSTALL_ROOT}/bin}"

validate_source() {
    if [[ "${SOURCE}" == "unknown" ]]; then
        return 0
    fi

    if [[ "${SOURCE}" =~ ^[A-Za-z0-9._-]+$ ]]; then
        return 0
    fi

    log_error "--source may only contain letters, numbers, dot, underscore, or dash."
    exit 1
}

validate_https_url() {
    local value="$1"
    local option_name="$2"

    if [[ -z "${value}" ]]; then
        return 0
    fi

    if [[ "${value}" == https://* ]]; then
        return 0
    fi

    log_error "${option_name} must start with https://"
    exit 1
}

validate_version() {
    if [[ "${VERSION}" == "latest" ]]; then
        return 0
    fi

    if [[ "${VERSION}" =~ ^v?[0-9]+\.[0-9]+\.[0-9]+([.-][A-Za-z0-9]+)*$ ]]; then
        return 0
    fi

    log_error "--version must be 'latest' or a semver string."
    exit 1
}

validate_github_repo() {
    local github_repo="${QWEN_INSTALL_GITHUB_REPO:-QwenLM/qwen-code}"
    if [[ "${github_repo}" =~ ^[A-Za-z0-9._-]+/[A-Za-z0-9._-]+$ ]]; then
        return 0
    fi

    log_error "QWEN_INSTALL_GITHUB_REPO must be in owner/repo format."
    exit 1
}

validate_install_path() {
    local value="$1"
    local option_name="$2"

    if [[ -z "${value}" ]]; then
        log_error "${option_name} must not be empty."
        exit 1
    fi

    case "${value}" in
        *$'\n'*|*$'\r'*)
            log_error "${option_name} must not contain newlines."
            exit 1
            ;;
    esac

    if [[ "${value}" != /* ]]; then
        log_error "${option_name} must be an absolute path."
        exit 1
    fi
}

validate_options() {
    METHOD="${METHOD:-detect}"

    case "${METHOD}" in
        detect|standalone|npm)
            ;;
        *)
            log_error "--method must be detect, standalone, or npm."
            exit 1
            ;;
    esac

    case "${MIRROR}" in
        auto|github|aliyun)
            ;;
        *)
            log_error "--mirror must be auto, github, or aliyun."
            exit 1
            ;;
    esac

    validate_https_url "${BASE_URL}" "--base-url"
    validate_https_url "${NPM_REGISTRY}" "--registry"
    validate_version
    validate_github_repo
    validate_install_path "${INSTALL_ROOT}" "QWEN_INSTALL_ROOT"
    validate_install_path "${INSTALL_LIB_PARENT}" "QWEN_INSTALL_LIB_PARENT"
    validate_install_path "${INSTALL_LIB_DIR}" "QWEN_INSTALL_LIB_DIR"
    validate_install_path "${INSTALL_BIN_DIR}" "QWEN_INSTALL_BIN_DIR"
    validate_source
}

while [[ $# -gt 0 ]]; do
    case "$1" in
        -s|--source)
            if [[ -z "${2:-}" ]] || [[ "${2:-}" == -* ]]; then
                log_error "--source requires a value"
                exit 1
            fi
            SOURCE="$2"
            shift 2
            ;;
        --method)
            if [[ -z "${2:-}" ]] || [[ "${2:-}" == -* ]]; then
                log_error "--method requires a value"
                exit 1
            fi
            METHOD="$2"
            shift 2
            ;;
        --mirror)
            if [[ -z "${2:-}" ]] || [[ "${2:-}" == -* ]]; then
                log_error "--mirror requires a value"
                exit 1
            fi
            MIRROR="$2"
            shift 2
            ;;
        --base-url)
            if [[ -z "${2:-}" ]] || [[ "${2:-}" == -* ]]; then
                log_error "--base-url requires a value"
                exit 1
            fi
            validate_https_url "$2" "--base-url"
            BASE_URL="$2"
            shift 2
            ;;
        --archive)
            if [[ -z "${2:-}" ]] || [[ "${2:-}" == -* ]]; then
                log_error "--archive requires a value"
                exit 1
            fi
            ARCHIVE_PATH="$2"
            shift 2
            ;;
        --version)
            if [[ -z "${2:-}" ]] || [[ "${2:-}" == -* ]]; then
                log_error "--version requires a value"
                exit 1
            fi
            VERSION="$2"
            shift 2
            ;;
        --registry)
            if [[ -z "${2:-}" ]] || [[ "${2:-}" == -* ]]; then
                log_error "--registry requires a value"
                exit 1
            fi
            NPM_REGISTRY="$2"
            shift 2
            ;;
        --no-modify-path)
            NO_MODIFY_PATH=1
            shift
            ;;
        -h|--help)
            print_usage
            exit 0
            ;;
        *)
            log_error "Unknown option: $1"
            echo ""
            print_usage
            exit 1
            ;;
    esac
done

# Validate all user-supplied options before doing network or filesystem work.
validate_options

print_header() {
    echo ""
    echo "Installing Qwen Code version: $(display_install_version)"
    echo ""
}

print_node_help() {
    echo ""
    echo "Node.js 22 or newer is required. Install from https://nodejs.org/ then rerun."
    echo "  brew install node"
}

require_node() {
    if ! command_exists node; then
        log_error "Node.js was not found."
        print_node_help
        return 1
    fi

    local node_version
    node_version=$(node -p "process.versions.node" 2>/dev/null || true)
    local node_major
    node_major=$(node -p "Number(process.versions.node.split('.')[0])" 2>/dev/null || true)

    if [[ -z "${node_major}" ]] || ! [[ "${node_major}" =~ ^[0-9]+$ ]]; then
        log_error "Unable to determine Node.js version."
        print_node_help
        return 1
    fi

    if [[ "${node_major}" -lt 22 ]]; then
        log_error "Node.js ${node_version:-unknown} is installed, but Node.js 22 or newer is required."
        print_node_help
        return 1
    fi
}

require_npm() {
    if command_exists npm; then
        return 0
    fi

    log_error "npm was not found. Install Node.js with npm from https://nodejs.org/"
    return 1
}

get_npm_global_bin() {
    local prefix
    prefix=$(npm prefix -g 2>/dev/null || true)

    if [[ -z "${prefix}" ]]; then
        return 0
    fi

    case "$(uname -s 2>/dev/null || echo unknown)" in
        MINGW*|MSYS*|CYGWIN*)
            echo "${prefix}"
            ;;
        *)
            echo "${prefix}/bin"
            ;;
    esac
}

get_npm_global_root() {
    npm root -g 2>/dev/null || true
}

create_source_json() {
    if [[ "${SOURCE}" == "unknown" ]]; then
        return 0
    fi

    local qwen_dir="${HOME}/.qwen"
    mkdir -p "${qwen_dir}"

    local escaped_source
    escaped_source=$(printf '%s' "${SOURCE}" | sed 's/\\/\\\\/g; s/"/\\"/g')

    cat > "${qwen_dir}/source.json" <<EOF
{
  "source": "${escaped_source}"
}
EOF
}

detect_target() {
    local os
    os=$(uname -s 2>/dev/null || echo unknown)
    local arch
    arch=$(uname -m 2>/dev/null || echo unknown)

    case "${os}" in
        Darwin)
            os="darwin"
            ;;
        Linux)
            os="linux"
            ;;
        *)
            return 1
            ;;
    esac

    case "${arch}" in
        x86_64|amd64)
            arch="x64"
            ;;
        arm64|aarch64)
            arch="arm64"
            ;;
        *)
            return 1
            ;;
    esac

    echo "${os}-${arch}"
}

archive_extension_for_target() {
    case "$1" in
        darwin-*|linux-*)
            echo "tar.gz"
            ;;
        *)
            return 1
            ;;
    esac
}

release_version_path() {
    if [[ "${VERSION}" == "latest" ]]; then
        echo "latest"
        return 0
    fi

    case "${VERSION}" in
        v*)
            echo "${VERSION}"
            ;;
        *)
            echo "v${VERSION}"
            ;;
    esac
}

# When a shadowing 'qwen' is detected, append a PATH prepend to the user's
# shell rc file at the very end. Putting it at the END means our prepend runs
# AFTER any earlier PATH munging in the rc file (e.g., other tools' shell
# init), so our installed_bin wins. Idempotent via a marker comment.
maybe_update_shell_path() {
    local install_bin_dir="$1"

    [[ "${NO_MODIFY_PATH:-0}" == "1" ]] && return 0
    [[ -z "${install_bin_dir}" ]] && return 0
    [[ -z "${HOME:-}" ]] && return 0

    local rc_file=""
    case "${SHELL:-}" in
        */zsh)  rc_file="${HOME}/.zshrc" ;;
        */bash)
            if [[ -f "${HOME}/.bashrc" ]]; then
                rc_file="${HOME}/.bashrc"
            elif [[ -f "${HOME}/.bash_profile" ]]; then
                rc_file="${HOME}/.bash_profile"
            else
                rc_file="${HOME}/.bashrc"
            fi
            ;;
        */fish) rc_file="${HOME}/.config/fish/config.fish" ;;
        *)
            log_warning "Unsupported shell for automatic PATH update: ${SHELL:-unknown}. Add ${install_bin_dir} to PATH manually."
            return 0
            ;;
    esac

    [[ -z "${rc_file}" ]] && return 0

    local begin_marker="# Qwen Code PATH block begin"
    local end_marker="# Qwen Code PATH block end"
    local quoted_install_bin_dir
    quoted_install_bin_dir=$(shell_quote "${install_bin_dir}")
    local export_line
    if [[ "${rc_file}" == *config.fish ]]; then
        export_line="set -gx PATH ${quoted_install_bin_dir} \$PATH"
    else
        export_line="export PATH=${quoted_install_bin_dir}:\$PATH"
    fi

    if [[ -f "${rc_file}" ]] && grep -qxF "${export_line}" "${rc_file}" 2>/dev/null; then
        local current_tail
        current_tail=$(tail -n 3 "${rc_file}" 2>/dev/null || true)
        if [[ "${current_tail}" == "${begin_marker}"$'\n'"${export_line}"$'\n'"${end_marker}" ]]; then
            PATH_UPDATE_APPLIED=1
            PATH_UPDATE_RC_FILE="${rc_file}"
            return 0
        fi
    fi

    mkdir -p "$(dirname "${rc_file}")" 2>/dev/null || true
    {
        echo ""
        echo "${begin_marker}"
        echo "${export_line}"
        echo "${end_marker}"
    } >> "${rc_file}" || {
        log_warning "Could not write PATH update to ${rc_file}."
        return 0
    }

    PATH_UPDATE_APPLIED=1
    PATH_UPDATE_RC_FILE="${rc_file}"
}

github_base_url_for_version() {
    local version_path="$1"
    local github_repo="${QWEN_INSTALL_GITHUB_REPO:-QwenLM/qwen-code}"
    if [[ "${version_path}" == "latest" ]]; then
        echo "https://github.com/${github_repo}/releases/latest/download"
    else
        echo "https://github.com/${github_repo}/releases/download/${version_path}"
    fi
}

aliyun_base_url_for_version() {
    local version_path="$1"
    echo "https://qwen-code-assets.oss-cn-hangzhou.aliyuncs.com/releases/qwen-code/${version_path}"
}

aliyun_latest_version_url() {
    echo "https://qwen-code-assets.oss-cn-hangzhou.aliyuncs.com/releases/qwen-code/latest/VERSION"
}

normalize_version_path_value() {
    local raw_version="$1"
    local version_path

    raw_version=$(printf '%s' "${raw_version}" | tr -d '\r' | awk 'NF { print $1; exit }')
    if [[ -z "${raw_version}" ]]; then
        return 1
    fi

    case "${raw_version}" in
        v*)
            version_path="${raw_version}"
            ;;
        *)
            version_path="v${raw_version}"
            ;;
    esac

    if [[ "${version_path}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+([.-][A-Za-z0-9]+)*$ ]]; then
        echo "${version_path}"
        return 0
    fi

    return 1
}

download_text() {
    local url="$1"

    if command_exists curl; then
        curl -fsSL --retry 2 --connect-timeout 10 --max-time 30 "${url}"
        return $?
    fi

    if command_exists wget; then
        local wget_args=(--tries=3 --timeout=10)
        if wget --help 2>&1 | grep -q -- '--read-timeout'; then
            wget_args+=(--read-timeout=30)
        fi
        wget -q "${wget_args[@]}" -O - "${url}"
        return $?
    fi

    log_error "curl or wget is required to resolve the standalone release version."
    return 1
}

resolve_aliyun_version_path() {
    local version_path="$1"

    if [[ "${version_path}" != "latest" ]]; then
        echo "${version_path}"
        return 0
    fi

    local latest_url
    latest_url=$(aliyun_latest_version_url)

    local latest_version
    if ! latest_version=$(download_text "${latest_url}"); then
        log_warning "Failed to resolve Aliyun latest VERSION pointer." >&2
        return 1
    fi

    local resolved_version_path
    if ! resolved_version_path=$(normalize_version_path_value "${latest_version}"); then
        log_error "Aliyun latest VERSION pointer is not a valid semver value."
        return 1
    fi

    : # resolved to ${resolved_version_path}
    echo "${resolved_version_path}"
}

# Probe a URL with a HEAD request first, then fall back to a 1-byte ranged GET
# for object stores or CDNs that reject HEAD while still serving the object.
probe_url_available() {
    local url="$1"
    local timeout="${2:-30}"

    if command_exists curl; then
        if curl -fsIL --retry 1 --connect-timeout 10 --max-time "${timeout}" "${url}" >/dev/null 2>&1; then
            return 0
        fi
        curl -fsL --retry 1 --connect-timeout 10 --max-time "${timeout}" \
            --range 0-0 -o /dev/null "${url}" >/dev/null 2>&1
        return $?
    fi

    if command_exists wget; then
        local wget_args=(--tries=2 --timeout=10)
        if wget --help 2>&1 | grep -q -- '--read-timeout'; then
            wget_args+=(--read-timeout="${timeout}")
        fi
        if wget -q --spider "${wget_args[@]}" "${url}" >/dev/null 2>&1; then
            return 0
        fi
        wget -q "${wget_args[@]}" --header='Range: bytes=0-0' -O /dev/null "${url}" >/dev/null 2>&1
        return $?
    fi

    return 1
}

# Race two availability probes; print "aliyun" or "github" based on which
# mirror's SHA256SUMS responds first, or "timeout" if neither responds before
# the deadline. Caller decides what to do with "timeout" (currently: log it and
# fall back to github).
race_mirror_head() {
    local timeout="${1:-2}"
    local gh_url="$2"
    local oss_url="$3"
    local tmpdir
    if ! tmpdir=$(mktemp -d -t qwen-mirror.XXXXXX 2>/dev/null); then
        # Refuse to fall back to a predictable PID-based path; a local attacker
        # could pre-create it to influence mirror selection.
        echo "mirror probe: mktemp failed" >&2
        echo "github"
        return 0
    fi
    register_temp_dir "${tmpdir}"

    (probe_url_available "${oss_url}" "${timeout}" && : > "${tmpdir}/aliyun") &
    local oss_pid=$!
    (probe_url_available "${gh_url}" "${timeout}" && : > "${tmpdir}/github") &
    local gh_pid=$!

    local winner=""
    local elapsed=0
    local max=$((timeout * 10 + 5))
    while [[ -z "${winner}" && "${elapsed}" -lt "${max}" ]]; do
        # Probe OSS first to break ties in favor of the closer mirror for CN users.
        [[ -e "${tmpdir}/aliyun" ]] && winner="aliyun" && break
        [[ -e "${tmpdir}/github" ]] && winner="github" && break
        sleep 0.1
        elapsed=$((elapsed + 1))
    done

    kill "${oss_pid}" "${gh_pid}" 2>/dev/null || true
    wait "${oss_pid}" "${gh_pid}" 2>/dev/null || true
    rm -rf "${tmpdir}" 2>/dev/null || true

    echo "${winner:-timeout}"
}

standalone_base_url() {
    if [[ -n "${BASE_URL}" ]]; then
        echo "${BASE_URL%/}"
        return 0
    fi

    local version_path
    version_path=$(release_version_path)

    if [[ "${MIRROR}" == "auto" ]]; then
        local gh_head oss_head selected
        gh_head="$(github_base_url_for_version "${version_path}")/SHA256SUMS"
        if [[ "${version_path}" == "latest" ]]; then
            oss_head="$(aliyun_latest_version_url)"
        else
            oss_head="$(aliyun_base_url_for_version "${version_path}")/SHA256SUMS"
        fi
        selected=$(race_mirror_head 2 "${gh_head}" "${oss_head}")
        if [[ "${selected}" == "timeout" ]]; then
            selected="github"
        fi
        MIRROR="${selected}"
    fi

    if [[ "${MIRROR}" == "aliyun" ]]; then
        if ! version_path=$(resolve_aliyun_version_path "${version_path}"); then
            return 1
        fi
        aliyun_base_url_for_version "${version_path}"
        return 0
    fi

    github_base_url_for_version "${version_path}"
}

get_content_length() {
    local url="$1"
    curl -fsSLI --retry 1 --connect-timeout 10 --max-time 15 "${url}" 2>/dev/null \
        | grep -i '^content-length:' | tail -1 | tr -d '\r' | awk '{print $2}'
}

download_with_progress() {
    local url="$1"
    local output="$2"

    if ! command_exists curl || ! is_terminal; then
        download_file_simple "$url" "$output"
        return $?
    fi

    local content_length
    content_length=$(get_content_length "${url}")

    if [[ -z "${content_length}" ]] || [[ "${content_length}" -le 0 ]] 2>/dev/null; then
        download_file_simple "$url" "$output"
        return $?
    fi

    # Skip progress bar for small files (e.g. SHA256SUMS)
    if [[ "${content_length}" -lt 102400 ]] 2>/dev/null; then
        curl -fsSL --retry 2 --connect-timeout 15 --max-time 300 "${url}" -o "${output}"
        return $?
    fi

    printf "\033[?25l" >&2
    print_progress 0 "${content_length}"

    curl -fsSL --retry 2 --connect-timeout 15 --max-time 300 "${url}" -o "${output}" &
    ACTIVE_DOWNLOAD_PID=$!

    while kill -0 "${ACTIVE_DOWNLOAD_PID}" 2>/dev/null; do
        if [[ -f "${output}" ]]; then
            local file_size
            file_size=$(wc -c < "${output}" 2>/dev/null | tr -d ' ')
            if [[ -n "${file_size}" && "${file_size}" -gt 0 ]] 2>/dev/null; then
                print_progress "${file_size}" "${content_length}"
            fi
        fi
        sleep 1
    done

    wait "${ACTIVE_DOWNLOAD_PID}"
    local exit_code=$?
    ACTIVE_DOWNLOAD_PID=""
    printf "\033[?25h" >&2

    if [[ $exit_code -eq 0 ]]; then
        finish_progress
    else
        echo "" >&2
    fi
    return $exit_code
}

download_file_simple() {
    local url="$1"
    local destination="$2"

    if command_exists curl; then
        curl -fL --retry 2 --connect-timeout 15 --max-time 300 --progress-bar "${url}" -o "${destination}"
        return $?
    fi

    if command_exists wget; then
        local wget_args=(--tries=3 --timeout=15)
        if wget --help 2>&1 | grep -q -- '--read-timeout'; then
            wget_args+=(--read-timeout=300)
        fi
        if wget --help 2>&1 | grep -q -- '--progress'; then
            wget --progress=bar:force:noscroll "${wget_args[@]}" "${url}" -O "${destination}" &
            ACTIVE_DOWNLOAD_PID=$!
            wait "${ACTIVE_DOWNLOAD_PID}"
            local exit_code=$?
            ACTIVE_DOWNLOAD_PID=""
            return "${exit_code}"
        else
            wget "${wget_args[@]}" "${url}" -O "${destination}" &
            ACTIVE_DOWNLOAD_PID=$!
            wait "${ACTIVE_DOWNLOAD_PID}"
            local exit_code=$?
            ACTIVE_DOWNLOAD_PID=""
            return "${exit_code}"
        fi
    fi

    log_error "curl or wget is required to download the standalone archive."
    return 1
}

download_file() {
    local url="$1"
    local destination="$2"

    download_with_progress "${url}" "${destination}"
}

url_exists() {
    local url="$1"

    probe_url_available "${url}" 30
}

sha256_file() {
    local file_path="$1"

    if command_exists sha256sum; then
        sha256sum "${file_path}" | awk '{print $1}'
        return 0
    fi

    if command_exists shasum; then
        shasum -a 256 "${file_path}" | awk '{print $1}'
        return 0
    fi

    return 1
}

verify_checksum() {
    local archive_path="$1"
    local checksum_source="$2"
    local archive_name="$3"
    local checksum_file="${checksum_source}"
    local temp_checksum=""

    if [[ -z "${checksum_file}" ]]; then
        checksum_file="$(dirname "${archive_path}")/SHA256SUMS"
    elif [[ "${checksum_file}" == http://* || "${checksum_file}" == https://* ]]; then
        temp_checksum="$(mktemp)"
        if ! download_file "${checksum_file}" "${temp_checksum}"; then
            rm -f "${temp_checksum}"
            log_error "Could not download SHA256SUMS for checksum verification."
            return 1
        fi
        checksum_file="${temp_checksum}"
    fi

    if [[ ! -f "${checksum_file}" ]]; then
        rm -f "${temp_checksum}"
        log_error "SHA256SUMS not found at ${checksum_file}; cannot verify archive."
        return 1
    fi

    local expected
    expected=$(awk -v archive_name="${archive_name}" '
        {
            name = $2
            sub(/^\*/, "", name)
            if (name == archive_name) {
                print $1
                exit
            }
        }
    ' "${checksum_file}")
    if [[ -z "${expected}" ]]; then
        rm -f "${temp_checksum}"
        log_error "Checksum entry for ${archive_name} not found."
        return 1
    fi

    local actual
    if ! actual=$(sha256_file "${archive_path}"); then
        rm -f "${temp_checksum}"
        log_error "No SHA-256 utility found; cannot verify archive."
        return 1
    fi

    rm -f "${temp_checksum}"

    if [[ "${expected}" != "${actual}" ]]; then
        log_error "Checksum mismatch for ${archive_name}: expected ${expected}, got ${actual}."
        return 1
    fi
}

validate_archive_entry_path() {
    local entry="$1"
    entry="${entry//\\//}"

    while [[ "${entry}" == ./* ]]; do
        entry="${entry#./}"
    done

    # Reject entries containing CR/LF so a `..\r` or `..\n` entry cannot
    # bypass the literal `..` glob below.
    case "${entry}" in
        *$'\r'*|*$'\n'*)
            log_error "Archive contains unsafe path with control character: ${entry}"
            return 1
            ;;
    esac

    case "${entry}" in
        ""|/*|..|../*|*/..|*/../*)
            log_error "Archive contains unsafe path: ${entry:-<empty>}"
            return 1
            ;;
    esac
}

archive_contains_symlinks_or_hardlinks() {
    local archive_path="$1"

    case "${archive_path}" in
        *.zip)
            unzip -Z -v "${archive_path}" 2>/dev/null | grep -E 'Unix file attributes \(12[0-7]{4} octal\)' >/dev/null
            ;;
        *.tar.gz|*.tgz|*.tar.xz)
            tar -tvf "${archive_path}" 2>/dev/null | awk '$1 ~ /^[lh]/ { found=1 } END { exit found ? 0 : 1 }'
            ;;
        *)
            return 1
            ;;
    esac
}

validate_archive_contents() {
    local archive_path="$1"
    local entries
    local entry

    case "${archive_path}" in
        *.zip)
            if ! command_exists unzip; then
                log_error "unzip is required to inspect ${archive_path}."
                return 1
            fi
            if ! entries=$(unzip -Z1 "${archive_path}"); then
                log_error "Failed to inspect archive entries: ${archive_path}"
                return 1
            fi
            ;;
        *.tar.gz|*.tgz|*.tar.xz)
            if ! entries=$(tar -tf "${archive_path}"); then
                log_error "Failed to inspect archive entries: ${archive_path}"
                return 1
            fi
            ;;
        *)
            log_error "Unsupported archive format: ${archive_path}"
            return 1
            ;;
    esac

    if [[ -z "${entries}" ]]; then
        log_error "Archive is empty: ${archive_path}"
        return 1
    fi

    if archive_contains_symlinks_or_hardlinks "${archive_path}"; then
        log_error "Archive contains symlinks or hardlinks; refusing to install."
        return 1
    fi

    while IFS= read -r entry; do
        validate_archive_entry_path "${entry}" || return 1
    done <<< "${entries}"
}

extract_archive() {
    local archive_path="$1"
    local destination="$2"

    mkdir -p "${destination}" || return 1
    validate_archive_contents "${archive_path}" || return 1

    case "${archive_path}" in
        *.zip)
            if ! command_exists unzip; then
                log_error "unzip is required to extract ${archive_path}."
                return 1
            fi
            unzip -q "${archive_path}" -d "${destination}" || return 1
            ;;
        *.tar.gz|*.tgz)
            tar -xzf "${archive_path}" -C "${destination}" || return 1
            ;;
        *.tar.xz)
            tar -xf "${archive_path}" -C "${destination}" || return 1
            ;;
        *)
            log_error "Unsupported archive format: ${archive_path}"
            return 1
            ;;
    esac

    local symlink_entry
    symlink_entry=$(find "${destination}" -type l -print | sed -n '1p')
    if [[ -n "${symlink_entry}" ]]; then
        log_error "Archive contains symlinks; refusing to install."
        return 1
    fi
}

ensure_managed_install_dir() {
    local install_dir="$1"

    if [[ ! -e "${install_dir}" ]]; then
        return 0
    fi

    if is_qwen_standalone_install_dir "${install_dir}"; then
        return 0
    fi

    local backup="${install_dir}.backup.$(date +%Y%m%dT%H%M%S 2>/dev/null || date +%Y%m%d%H%M%S)"
    log_warning "${install_dir} exists but is not a Qwen Code standalone install."
    log_warning "Backing up to: ${backup}"
    if mv "${install_dir}" "${backup}"; then
        return 0
    fi

    log_error "Failed to back up ${install_dir}. Move or remove it manually, then rerun the installer."
    return 1
}

restore_stale_install_backup() {
    local old_install_dir="$1"
    local current_install_dir="$2"

    if [[ -e "${current_install_dir}" || ! -e "${old_install_dir}" ]]; then
        return 0
    fi

    log_warning "Found previous install backup without an active install: ${old_install_dir}"
    log_warning "Restoring backup to ${current_install_dir} before continuing."
    if mv "${old_install_dir}" "${current_install_dir}"; then
        return 0
    fi

    log_error "Failed to restore previous install from ${old_install_dir}."
    return 1
}

is_qwen_standalone_install_dir() {
    local install_dir="$1"
    local manifest_path="${install_dir}/manifest.json"

    [[ -f "${manifest_path}" ]] || return 1
    # Manifest format is produced by writeManifest in create-standalone-package.js.
    # Keep these grep checks in sync if that JSON layout changes.
    grep -Eq '"name"[[:space:]]*:[[:space:]]*"@qwen-code/qwen-code"' "${manifest_path}" 2>/dev/null || return 1
    grep -Eq '"target"[[:space:]]*:[[:space:]]*"(darwin|linux)-(arm64|x64)"' "${manifest_path}" 2>/dev/null || return 1
    [[ -f "${install_dir}/bin/qwen" && ! -L "${install_dir}/bin/qwen" && -x "${install_dir}/bin/qwen" ]] || return 1
    [[ -f "${install_dir}/node/bin/node" && ! -L "${install_dir}/node/bin/node" && -x "${install_dir}/node/bin/node" ]] || return 1
}

write_unix_wrapper() {
    local wrapper_path="$1"
    local qwen_bin="$2"
    local quoted_qwen_bin
    quoted_qwen_bin=$(shell_quote "${qwen_bin}")

    if ! cat > "${wrapper_path}" <<EOF
#!/usr/bin/env sh
exec ${quoted_qwen_bin} "\$@"
EOF
    then
        return 1
    fi
    chmod +x "${wrapper_path}"
}

install_standalone() {
    # Return 2 only when a standalone archive is unavailable and detect mode may
    # fall back to npm. Return 1 for integrity or install failures that should
    # not be masked by an automatic fallback.
    local target=""
    local archive_name=""
    local archive_path=""
    local checksum_source=""
    local temp_dir=""

    # Resolve the archive from a local file or from the configured release mirror.
    if [[ -n "${ARCHIVE_PATH}" ]]; then
        archive_path="${ARCHIVE_PATH}"
        archive_name="$(basename "${archive_path}")"
        if [[ ! -f "${archive_path}" ]]; then
            log_error "Standalone archive not found: ${archive_path}"
            return 1
        fi
    else
        if ! target=$(detect_target); then
            log_warning "Standalone archive is not available for this platform."
            return 2
        fi

        local archive_extension
        archive_extension=$(archive_extension_for_target "${target}")
        archive_name="qwen-code-${target}.${archive_extension}"

        local requested_mirror="${MIRROR}"
        local requested_version_path=""
        local github_fallback_base_url=""
        if [[ -z "${BASE_URL}" && "${requested_mirror}" == "auto" ]]; then
            requested_version_path=$(release_version_path)
            github_fallback_base_url="$(github_base_url_for_version "${requested_version_path}")"
        fi

        local base_url
        if ! base_url=$(standalone_base_url); then
            if [[ -n "${github_fallback_base_url}" ]]; then
                log_warning "Aliyun standalone release metadata unavailable; retrying GitHub mirror."
                base_url="${github_fallback_base_url}"
                MIRROR="github"
                github_fallback_base_url=""
            else
                if [[ "${METHOD}" == "detect" ]]; then
                    return 2
                fi
                return 1
            fi
        fi
        if [[ -n "${github_fallback_base_url}" && "${requested_version_path}" == "latest" ]]; then
            local aliyun_release_base="https://qwen-code-assets.oss-cn-hangzhou.aliyuncs.com/releases/qwen-code/"
            if [[ "${base_url}" == "${aliyun_release_base}"* ]]; then
                local resolved_version_path="${base_url#"${aliyun_release_base}"}"
                if [[ -n "${resolved_version_path}" && "${resolved_version_path}" != "latest" && "${resolved_version_path}" != */* ]]; then
                    github_fallback_base_url="$(github_base_url_for_version "${resolved_version_path}")"
                fi
            fi
        fi
        if [[ "${base_url}" == "${github_fallback_base_url}" ]]; then
            github_fallback_base_url=""
        fi

        local archive_url="${base_url}/${archive_name}"
        checksum_source="${base_url}/SHA256SUMS"

        if [[ "${METHOD}" == "detect" ]] && ! url_exists "${archive_url}"; then
            if [[ -n "${github_fallback_base_url}" ]]; then
                local github_archive_url="${github_fallback_base_url}/${archive_name}"
                if url_exists "${github_archive_url}"; then
                    log_warning "Aliyun standalone archive not found; retrying GitHub mirror."
                    base_url="${github_fallback_base_url}"
                    archive_url="${github_archive_url}"
                    checksum_source="${base_url}/SHA256SUMS"
                    MIRROR="github"
                    github_fallback_base_url=""
                else
                    log_warning "Standalone archive not found: ${archive_name}"
                    return 2
                fi
            else
                log_warning "Standalone archive not found: ${archive_name}"
                return 2
            fi
        fi

        temp_dir=$(mktemp -d)
        register_temp_dir "${temp_dir}"
        archive_path="${temp_dir}/${archive_name}"

        log_info "Downloading ${archive_name}"
        if ! download_file "${archive_url}" "${archive_path}"; then
            if [[ -n "${github_fallback_base_url}" ]]; then
                rm -f "${archive_path}"
                archive_url="${github_fallback_base_url}/${archive_name}"
                checksum_source="${github_fallback_base_url}/SHA256SUMS"
                MIRROR="github"
                github_fallback_base_url=""
                log_warning "Aliyun standalone archive download failed; retrying GitHub mirror."
                if download_file "${archive_url}" "${archive_path}"; then
                    :
                else
                    rm -rf "${temp_dir}"
                    log_warning "Failed to download standalone archive."
                    if [[ "${METHOD}" == "detect" ]]; then
                        return 2
                    fi
                    return 1
                fi
            else
                rm -rf "${temp_dir}"
                log_warning "Failed to download standalone archive."
                if [[ "${METHOD}" == "detect" ]]; then
                    return 2
                fi
                return 1
            fi
        fi
    fi

    if [[ -z "${temp_dir}" ]]; then
        temp_dir=$(mktemp -d)
        register_temp_dir "${temp_dir}"
    fi

    if ! verify_checksum "${archive_path}" "${checksum_source}" "${archive_name}"; then
        rm -rf "${temp_dir}"
        return 1
    fi

    local extract_dir="${temp_dir}/extract"
    if ! extract_archive "${archive_path}" "${extract_dir}"; then
        rm -rf "${temp_dir}"
        return 1
    fi

    if [[ ! -f "${extract_dir}/qwen-code/bin/qwen" || -L "${extract_dir}/qwen-code/bin/qwen" || ! -x "${extract_dir}/qwen-code/bin/qwen" ]]; then
        log_error "Archive does not contain qwen-code/bin/qwen."
        rm -rf "${temp_dir}"
        return 1
    fi

    if [[ ! -f "${extract_dir}/qwen-code/node/bin/node" || -L "${extract_dir}/qwen-code/node/bin/node" || ! -x "${extract_dir}/qwen-code/node/bin/node" ]]; then
        log_error "Archive does not contain executable qwen-code/node/bin/node."
        rm -rf "${temp_dir}"
        return 1
    fi

    mkdir -p "${INSTALL_LIB_PARENT}" "${INSTALL_BIN_DIR}" || {
        rm -rf "${temp_dir}"
        return 1
    }

    # Stage into .new and keep .old so failed upgrades can roll back.
    local new_install_dir="${INSTALL_LIB_DIR}.new"
    local old_install_dir="${INSTALL_LIB_DIR}.old"
    local wrapper_tmp="${INSTALL_BIN_DIR}/qwen.new"
    if ! ensure_managed_install_dir "${INSTALL_LIB_DIR}" ||
        ! ensure_managed_install_dir "${new_install_dir}" ||
        ! ensure_managed_install_dir "${old_install_dir}"; then
        rm -rf "${temp_dir}"
        return 1
    fi
    if ! restore_stale_install_backup "${old_install_dir}" "${INSTALL_LIB_DIR}"; then
        rm -rf "${temp_dir}"
        return 1
    fi
    if [[ -e "${old_install_dir}" ]]; then
        rm -rf "${old_install_dir}" || {
            rm -rf "${temp_dir}"
            log_error "Failed to remove stale install backup: ${old_install_dir}"
            return 1
        }
    fi
    rm -rf "${new_install_dir}" "${wrapper_tmp}"
    mv "${extract_dir}/qwen-code" "${new_install_dir}"

    if ! write_unix_wrapper "${wrapper_tmp}" "${INSTALL_LIB_DIR}/bin/qwen"; then
        rm -rf "${temp_dir}" "${new_install_dir}" "${wrapper_tmp}"
        log_error "Failed to create qwen wrapper in ${INSTALL_BIN_DIR}."
        return 1
    fi

    # Suppress INT/TERM during the critical mv swap to avoid leaving
    # INSTALL_LIB_DIR absent if the user presses Ctrl+C between the two moves.
    trap '' INT TERM
    if [[ -e "${INSTALL_LIB_DIR}" ]]; then
        mv "${INSTALL_LIB_DIR}" "${old_install_dir}"
    fi

    if ! mv "${new_install_dir}" "${INSTALL_LIB_DIR}"; then
        if [[ -e "${old_install_dir}" ]]; then
            mv "${old_install_dir}" "${INSTALL_LIB_DIR}"
        fi
        trap 'restore_cursor >&2; kill_active_download; cleanup_temp_dirs; exit 130' INT
        trap 'restore_cursor >&2; kill_active_download; cleanup_temp_dirs; exit 143' TERM
        rm -rf "${temp_dir}" "${wrapper_tmp}"
        log_error "Failed to install standalone archive to ${INSTALL_LIB_DIR}."
        return 1
    fi
    trap 'restore_cursor >&2; kill_active_download; cleanup_temp_dirs; exit 130' INT
    trap 'restore_cursor >&2; kill_active_download; cleanup_temp_dirs; exit 143' TERM

    if ! mv -f "${wrapper_tmp}" "${INSTALL_BIN_DIR}/qwen"; then
        rm -rf "${INSTALL_LIB_DIR}" "${wrapper_tmp}"
        if [[ -e "${old_install_dir}" ]]; then
            mv "${old_install_dir}" "${INSTALL_LIB_DIR}"
        fi
        rm -rf "${temp_dir}"
        log_error "Failed to create qwen wrapper in ${INSTALL_BIN_DIR}."
        return 1
    fi

    rm -rf "${old_install_dir}"
    export PATH="${INSTALL_BIN_DIR}:${PATH}"

    create_source_json
    rm -rf "${temp_dir}"
}

npm_package_spec() {
    if [[ "${VERSION}" == "latest" ]]; then
        echo "@qwen-code/qwen-code@latest"
        return 0
    fi

    local npm_version="${VERSION#v}"
    echo "@qwen-code/qwen-code@${npm_version}"
}

install_npm() {
    require_node || return 1
    require_npm || return 1

    local package_spec
    package_spec=$(npm_package_spec)

    local install_cmd=(
        npm
        install
        -g
        "${package_spec}"
        --registry
        "${NPM_REGISTRY}"
    )

    if "${install_cmd[@]}"; then
        create_source_json
        return 0
    fi

    log_error "Failed to install. Try: npm install -g ${package_spec} --registry ${NPM_REGISTRY}"
    return 1
}

gradient_line() {
    local text="$1"
    local r1=$2 g1=$3 b1=$4
    local r2=$5 g2=$6 b2=$7
    local r3=$8 g3=$9 b3=${10}
    local len=${#text}
    [ "$len" -eq 0 ] && return
    if ! supports_truecolor; then
        printf "%b%s%b\n" "${BRAND_PURPLE}" "${text}" "${NC}"
        return
    fi
    local i=0
    local half=$(( len / 2 ))
    while [ $i -lt $len ]; do
        local char="${text:$i:1}"
        local r g b
        if [ $i -lt $half ]; then
            local t=$(( i * 1000 / half ))
            r=$(( (r1 * (1000 - t) + r2 * t) / 1000 ))
            g=$(( (g1 * (1000 - t) + g2 * t) / 1000 ))
            b=$(( (b1 * (1000 - t) + b2 * t) / 1000 ))
        else
            local t=$(( (i - half) * 1000 / (len - half) ))
            r=$(( (r2 * (1000 - t) + r3 * t) / 1000 ))
            g=$(( (g2 * (1000 - t) + g3 * t) / 1000 ))
            b=$(( (b2 * (1000 - t) + b3 * t) / 1000 ))
        fi
        if [ "$char" = " " ]; then
            printf " "
        else
            printf "\033[38;2;%d;%d;%dm%s" "$r" "$g" "$b" "$char"
        fi
        i=$(( i + 1 ))
    done
    printf "\033[0m\n"
}

print_logo() {
    # Per-character gradient matching CLI's ink-gradient rendering
    # Direction: #4796E4 (blue) → #847ACE (purple) → #C3677F (rose)
    gradient_line " ▄▄▄▄▄▄  ▄▄     ▄▄ ▄▄▄▄▄▄▄ ▄▄▄    ▄▄"  71 150 228  132 122 206  195 103 127
    gradient_line "██╔═══██╗██║    ██║██╔════╝████╗  ██║"  71 150 228  132 122 206  195 103 127
    gradient_line "██║   ██║██║ █╗ ██║█████╗  ██╔██╗ ██║"  71 150 228  132 122 206  195 103 127
    gradient_line "██║▄▄ ██║██║███╗██║██╔══╝  ██║╚██╗██║"  71 150 228  132 122 206  195 103 127
    gradient_line "╚██████╔╝╚███╔███╔╝███████╗██║ ╚████║"  71 150 228  132 122 206  195 103 127
    gradient_line " ╚══▀▀═╝  ╚══╝╚══╝ ╚══════╝╚═╝  ╚═══╝"  71 150 228  132 122 206  195 103 127
}

print_final_instructions() {
    local install_bin_dir="${1:-}"
    local install_dir="${2:-}"
    local install_method="${3:-standalone}"
    local installed_bin=""
    local standalone_uninstall_url="https://qwen-code-assets.oss-cn-hangzhou.aliyuncs.com/installation/uninstall-qwen-standalone.sh"
    if [[ -n "${install_bin_dir}" ]]; then
        installed_bin="${install_bin_dir}/qwen"
        export PATH="${install_bin_dir}:${PATH}"
    fi

    # Detect shadowing qwen executables
    local other_qwens=""
    if [[ -n "${PRE_INSTALL_QWENS:-}" ]]; then
        local saved_ifs="${IFS}"
        IFS=$'\n'
        local path
        for path in ${PRE_INSTALL_QWENS}; do
            [[ -z "${path}" ]] && continue
            [[ -n "${installed_bin}" && "${path}" == "${installed_bin}" ]] && continue
            if [[ -z "${other_qwens}" ]]; then
                other_qwens="${path}"
            else
                other_qwens="${other_qwens}"$'\n'"${path}"
            fi
        done
        IFS="${saved_ifs}"
    fi

    if [[ -n "${install_bin_dir}" && "${NO_MODIFY_PATH:-0}" != "1" ]]; then
        PATH_UPDATE_APPLIED=0
        PATH_UPDATE_RC_FILE=""
        maybe_update_shell_path "${install_bin_dir}"
    fi

    local installed_version="unknown"
    if [[ -n "${installed_bin}" && -x "${installed_bin}" ]]; then
        installed_version=$("${installed_bin}" --version 2>/dev/null || echo "unknown")
    elif command_exists qwen; then
        installed_version=$(qwen --version 2>/dev/null || echo "unknown")
    fi

    # Display the rc file maybe_update_shell_path actually wrote to (e.g. bash
    # may fall back to ~/.bash_profile), so the success message and the reload
    # hint can never point at a different file than the one that was modified.
    local rc_name="${PATH_UPDATE_RC_FILE:-}"
    if [[ -n "${rc_name}" && -n "${HOME:-}" && "${rc_name}" == "${HOME}"/* ]]; then
        rc_name="~${rc_name#"${HOME}"}"
    fi
    if [[ "${PATH_UPDATE_APPLIED:-0}" == "1" && -n "${rc_name}" ]]; then
        echo -e "${MUTED}Successfully added${NC} qwen ${MUTED}to \$PATH in${NC} ${rc_name}"
    fi

    # The invoking shell keeps its original PATH (and possibly an older qwen
    # resolved from it) until the rc file is reloaded. Detect both cases and
    # tell the user exactly what to run instead of letting `qwen` silently
    # launch a stale version.
    local shell_reload_needed=0
    if [[ -n "${install_bin_dir}" ]]; then
        case ":${ORIGINAL_PATH}:" in
            *":${install_bin_dir}:"*) ;;
            *) shell_reload_needed=1 ;;
        esac
    fi
    if [[ -n "${other_qwens}" ]]; then
        shell_reload_needed=1
        log_warning "Other qwen executables were found and may shadow the new install in this shell:"
        local shadow_path
        while IFS= read -r shadow_path; do
            [[ -z "${shadow_path}" ]] && continue
            printf '  %s\n' "${shadow_path}"
        done <<< "${other_qwens}"
    fi

    local reload_cmd=""
    if [[ "${shell_reload_needed}" == "1" ]]; then
        if [[ "${PATH_UPDATE_APPLIED:-0}" == "1" && -n "${rc_name}" ]]; then
            reload_cmd="source ${rc_name}"
        elif [[ -n "${install_bin_dir}" ]]; then
            log_warning "Make sure ${install_bin_dir} comes first on your PATH, then open a new terminal."
        fi
    fi

    echo ""
    echo -e "${MUTED}Qwen Code ${installed_version} installed successfully, to start:${NC}"
    echo ""
    if [[ -n "${reload_cmd}" ]]; then
        echo -e "${reload_cmd}  ${MUTED}# Load new PATH (or open a new terminal)${NC}"
    fi
    echo -e "cd <project>  ${MUTED}# Open directory${NC}"
    echo -e "qwen          ${MUTED}# Run command${NC}"
    echo ""
    echo -e "${MUTED}For more information visit ${NC}https://github.com/QwenLM/qwen-code"
    echo ""
}

main() {
    if [[ -z "${HOME:-}" ]]; then
        log_error "HOME is not set; cannot determine where to install Qwen Code."
        exit 1
    fi

    # Discover all qwen executables on disk BEFORE we install, so the
    # just-installed binary doesn't pollute the search. We can't reliably
    # simulate the user's interactive shell PATH (some tools inject their
    # bin only under a tty), so we enumerate well-known per-tool bin
    # directories plus whatever bash inherited on PATH.
    PRE_INSTALL_QWENS=$(
        {
            IFS=:
            for dir in $PATH; do
                [[ -z "${dir}" ]] && continue
                [[ -x "${dir}/qwen" ]] && echo "${dir}/qwen"
            done
            for candidate in \
                "${HOME}/.opencode/bin/qwen" \
                "${HOME}/.bun/bin/qwen" \
                "${HOME}/.cargo/bin/qwen" \
                "${HOME}/.deno/bin/qwen" \
                "${HOME}/.volta/bin/qwen" \
                "${HOME}/.fnm/bin/qwen" \
                "${HOME}/.local/bin/qwen" \
                "${HOME}/Library/pnpm/qwen" \
                "/usr/local/bin/qwen" \
                "/opt/homebrew/bin/qwen"; do
                [[ -x "${candidate}" ]] && echo "${candidate}"
            done
            if command_exists npm; then
                local npm_prefix
                npm_prefix=$(npm prefix -g 2>/dev/null || true)
                if [[ -n "${npm_prefix}" && -x "${npm_prefix}/bin/qwen" ]]; then
                    echo "${npm_prefix}/bin/qwen"
                fi
            fi
        } 2>/dev/null | sort -u
    )
    export PRE_INSTALL_QWENS

    print_header

    case "${METHOD}" in
        standalone)
            install_standalone
            print_final_instructions "${INSTALL_BIN_DIR}" "${INSTALL_LIB_DIR}" "standalone"
            ;;
        npm)
            install_npm
            print_final_instructions "$(get_npm_global_bin)" "$(get_npm_global_root)" "npm"
            ;;
        detect)
            if install_standalone; then
                print_final_instructions "${INSTALL_BIN_DIR}" "${INSTALL_LIB_DIR}" "standalone"
            else
                standalone_status=$?
                if [[ "${standalone_status}" -eq 2 ]]; then
                    log_warning "Falling back to npm installation."
                    if install_npm; then
                        print_final_instructions "$(get_npm_global_bin)" "$(get_npm_global_root)" "npm"
                    else
                        log_error "Standalone archive was unavailable; npm fallback also failed."
                        exit 1
                    fi
                else
                    log_error "Standalone install failed. Retry with --method npm to use npm, or --method standalone to debug."
                    exit "${standalone_status}"
                fi
            fi
            ;;
    esac
}

main "$@"
