#!/usr/bin/env bash
# cspkg 一键安装：探测 LAN/公网 Generic Package，按本机平台下载单二进制。
# 真源：casstk/cspkg scripts/install.sh（安装门户短入口会复制一份）。
set -euo pipefail

LAN="${CSPKG_PACKAGE_LAN:-http://192.168.3.8:8899/api/v4/projects/casstk%2Fcspkg/packages/generic/cspkg/}"
INET="${CSPKG_PACKAGE_INTERNET:-http://112.74.47.129:8899/api/v4/projects/casstk%2Fcspkg/packages/generic/cspkg/}"
HTTP_LAN="${CSPKG_HTTP_LAN:-http://192.168.3.9/sa2/tools/cspkg/}"
HTTP_INET="${CSPKG_HTTP_INET:-http://sc.casstk.com/sa2/tools/cspkg/}"
VER="${CSPKG_VERSION:-latest}"
MIN_BYTES="${CSPKG_MIN_BYTES:-1048576}"

log() { echo "[cspkg-install] $*" >&2; }
die() { echo "[cspkg-install] $*" >&2; exit 1; }

# Generic：<ver>/<file>；HTTP：先 <ver>/ 与 latest/，扁平根目录作最后一档。
candidate_urls() {
    local fname=$1
    local base
    if [[ -n "${CSPKG_PACKAGE_BASE:-}" ]]; then
        base="${CSPKG_PACKAGE_BASE%/}"
        echo "${base}/${VER}/${fname}"
        echo "${base}/latest/${fname}"
        echo "${base}/${fname}"
        return
    fi
    echo "${LAN%/}/${VER}/${fname}"
    echo "${INET%/}/${VER}/${fname}"
    echo "${HTTP_LAN%/}/${VER}/${fname}"
    echo "${HTTP_LAN%/}/latest/${fname}"
    echo "${HTTP_LAN%/}/${fname}"
    echo "${HTTP_INET%/}/${VER}/${fname}"
    echo "${HTTP_INET%/}/latest/${fname}"
    echo "${HTTP_INET%/}/${fname}"
}

file_size() {
    wc -c < "$1" | tr -d '[:space:]'
}

hex4() {
    od -An -tx1 -N4 "$1" 2>/dev/null | tr -d '[:space:]' | tr 'A-F' 'a-f'
}

looks_like_bin() {
    local hex
    hex="$(hex4 "$1")"
    case "$hex" in
        7f454c46*) return 0 ;; # ELF
        cffaedfe*|feedfacf*|cefaedfe*|feedface*|cafebabe*) return 0 ;; # Mach-O / fat
        4d5a*) return 0 ;; # PE
    esac
    return 1
}

file_sha256() {
    if command -v sha256sum >/dev/null 2>&1; then
        sha256sum "$1" | awk '{print $1}'
    else
        shasum -a 256 "$1" | awk '{print $1}'
    fi
}

# 有 sidecar 则必须匹配；没有则只靠体积 + 魔数。
accept_download() {
    local f="$1"
    local src="$2"
    local sz want got sum
    sz="$(file_size "$f")"
    if [[ -z "$sz" || "$sz" -lt "$MIN_BYTES" ]]; then
        log "拒绝 ${src} (size ${sz:-0} < ${MIN_BYTES})"
        return 1
    fi
    if ! looks_like_bin "$f"; then
        log "拒绝 ${src} (not ELF/Mach-O/PE)"
        return 1
    fi
    sum="$(mktemp)"
    if curl -fsSL --connect-timeout 5 --max-time 20 -o "$sum" "${src}.sha256" 2>/dev/null; then
        want="$(awk '{print $1}' "$sum" | tr -d '[:space:]' | tr 'A-F' 'a-f')"
        rm -f "$sum"
        if [[ ! "$want" =~ ^[0-9a-f]{64}$ ]]; then
            log "sidecar 不是 sha256，按无校验继续"
        else
            got="$(file_sha256 "$f" | tr 'A-F' 'a-f')"
            if [[ "$want" != "$got" ]]; then
                log "拒绝 ${src} (SHA256 mismatch)"
                return 1
            fi
            log "SHA256 校验通过"
            return 0
        fi
    fi
    rm -f "$sum"
    log "无 sidecar，已用魔数+体积验收"
    return 0
}

# linux_amd64 / darwin_arm64 / windows_amd64。CSPKG_PLATFORM 优先于 SA2_PLATFORM。
normalize_plat() {
    local p
    p="$(printf '%s' "$1" | tr 'A-Z' 'a-z')"
    p="${p//-/_}"
    p="${p//\//_}"
    p="${p%_docker}"
    case "$p" in
        linux_x86_64|linux_x64|linux_amd64) echo linux_amd64 ;;
        linux_aarch64|linux_arm64) echo linux_arm64 ;;
        linux_armv7l|linux_armv7|linux_armhf|linux_arm) echo linux_arm ;;
        darwin_x86_64|darwin_x64|darwin_amd64|macos_amd64|macos_x86_64) echo darwin_amd64 ;;
        darwin_aarch64|darwin_arm64|macos_arm64) echo darwin_arm64 ;;
        windows_x86_64|windows_x64|windows_amd64) echo windows_amd64 ;;
        windows_aarch64|windows_arm64) echo windows_arm64 ;;
        *) return 1 ;;
    esac
}

detect_plat() {
    local override os arch plat
    override="${CSPKG_PLATFORM:-${SA2_PLATFORM:-}}"
    if [[ -n "$override" ]]; then
        if plat="$(normalize_plat "$override")"; then
            echo "$plat"
            return
        fi
        die "不支持的 CSPKG_PLATFORM/SA2_PLATFORM: $override"
    fi
    case "$(uname -s)" in
        Linux) os=linux ;;
        Darwin) os=darwin ;;
        MINGW*|MSYS*|CYGWIN*) die "Windows 请用: irm http://192.168.3.9/sa2/install/cspkg.ps1 | iex" ;;
        *) die "不支持的系统: $(uname -s)" ;;
    esac
    case "$(uname -m)" in
        x86_64|amd64) arch=amd64 ;;
        aarch64|arm64) arch=arm64 ;;
        armv7l|armv7|arm) arch=arm ;;
        *) die "不支持的架构: $(uname -m)" ;;
    esac
    # Apple Silicon 在 Rosetta 下 uname -m 是 x86_64；装本机 arm64。
    if [[ "$os" == darwin && "$arch" == amd64 ]]; then
        if [[ "$(sysctl -n sysctl.proc_translated 2>/dev/null || echo 0)" == 1 ]]; then
            arch=arm64
        fi
    fi
    echo "${os}_${arch}"
}

if [[ "${CSPKG_INSTALL_SELFTEST:-}" == 1 ]]; then
    unset CSPKG_PACKAGE_BASE CSPKG_VERSION || true
    VER=latest
    fail=0
    got="$(CSPKG_PACKAGE_BASE=http://example.test/cspkg VER=latest candidate_urls cspkg-linux_amd64 | tr '\n' ' ')"
    case "$got" in
        *"http://example.test/cspkg/latest/cspkg-linux_amd64"*"http://example.test/cspkg/cspkg-linux_amd64"*) ;;
        *) echo "candidate override failed: $got" >&2; fail=1 ;;
    esac
    got="$(unset CSPKG_PACKAGE_BASE; candidate_urls cspkg-linux_amd64 | tr '\n' ' ')"
    case "$got" in
        *"/sa2/tools/cspkg/latest/cspkg-linux_amd64"*) ;;
        *) echo "http latest candidate missing: $got" >&2; fail=1 ;;
    esac
    got="$(unset CSPKG_PACKAGE_BASE; candidate_urls cspkg-darwin_arm64 | head -n1)"
    [[ "$got" == *"/latest/cspkg-darwin_arm64" ]] || { echo "default gitlab layout: $got" >&2; fail=1; }
    empty="$(mktemp)"
    if accept_download "$empty" "http://example.test/empty"; then
        echo "empty file accepted" >&2
        fail=1
    fi
    rm -f "$empty"
    got="$(CSPKG_PLATFORM=linux_arm64 SA2_PLATFORM=windows_amd64 detect_plat)"
    [[ "$got" == linux_arm64 ]] || { echo "CSPKG_PLATFORM should win: $got" >&2; fail=1; }
    got="$(CSPKG_PLATFORM=Linux/x86_64 detect_plat)"
    [[ "$got" == linux_amd64 ]] || { echo "normalize linux/x86_64: $got" >&2; fail=1; }
    got="$(CSPKG_PLATFORM=windows_amd64 detect_plat)"
    [[ "$got" == windows_amd64 ]] || { echo "normalize windows_amd64: $got" >&2; fail=1; }
    if (CSPKG_PLATFORM=freebsd_amd64 detect_plat) >/dev/null 2>&1; then
        echo "invalid CSPKG_PLATFORM accepted" >&2
        fail=1
    fi
    [[ "$fail" -eq 0 ]] || exit 1
    echo "install.sh self-test ok"
    exit 0
fi

PLAT="$(detect_plat)"
FNAME="cspkg-${PLAT}"
if [[ "$PLAT" == windows_* ]]; then
    FNAME="${FNAME}.exe"
fi
log "平台 $PLAT  版本 $VER"

TMP="$(mktemp)"
trap 'rm -f "$TMP"' EXIT
OK=0
# 真源 casstk/cspkg Generic Package（public，匿名可拉）；到不了 :8899 再走 HTTP 镜像。
while IFS= read -r url; do
    [[ -n "$url" ]] || continue
    log "尝试 $url"
    if curl -fsSL --connect-timeout 8 --max-time 300 -o "$TMP" "$url" && accept_download "$TMP" "$url"; then
        OK=1
        break
    fi
done < <(candidate_urls "$FNAME")
[[ "$OK" -eq 1 ]] || die "下载失败（制品库需登录时请走 HTTP 镜像）"
chmod +x "$TMP"

DEST="${CSPKG_INSTALL_PREFIX:-/usr/local/bin}/cspkg"
if [[ -w "$(dirname "$DEST")" ]] || [[ "$(id -u)" -eq 0 ]]; then
    install -m 755 "$TMP" "$DEST"
else
    if command -v sudo >/dev/null 2>&1; then
        sudo install -m 755 "$TMP" "$DEST"
    else
        home="${HOME:-}"
        [[ -n "$home" ]] || die "HOME 未设置，无法装到 ~/.local/bin"
        DEST="${home}/.local/bin/cspkg"
        mkdir -p "$(dirname "$DEST")"
        install -m 755 "$TMP" "$DEST"
        log "已装到 $DEST（请保证 ~/.local/bin 在 PATH）"
    fi
fi
log "已安装 $DEST"
"$DEST" version
"$DEST" scan >/dev/null 2>&1 || true
echo
echo "下一步:  cspkg help"
echo "         cspkg search"
echo "         sudo cspkg install sa1 -y     # 或 sa2"
