#!/usr/bin/env bash
#
# install.sh - macOS / Linux 一键安装 nbskills 原生 CLI（脱离 npm）。
#
# 用法：
#   curl -fsSL https://jps-cli.devtestapp.com/nbskills/install.sh | bash
#   curl -fsSL https://jps-cli.devtestapp.com/nbskills/install.sh | bash -s -- --version 1.8.4
#   curl -fsSL https://jps-cli.devtestapp.com/nbskills/install.sh | bash -s -- --no-bootstrap
#
# 安装布局与 Web 自更新、GUI(cli_link.go)一致：
#   二进制：~/.local/share/nbskills/versions/<version>/nbskills
#   入口软链：~/.local/bin/nbskills  ← 与 GUI「链接命令行」目录同一处
#   PATH：写 ~/.zshrc ~/.bashrc ~/.profile，带标记做幂等去重
#
set -euo pipefail

DEFAULT_BASE_URL="https://jps-cli.devtestapp.com/nbskills"
BASE_URL="${NBSKILLS_INSTALL_BASE_URL:-${DEFAULT_BASE_URL}}"
VERSION="${NBSKILLS_INSTALL_VERSION:-}"
RUN_BOOTSTRAP=1
RC_MARKER="# added by nbskills installer"   # 必须与 GUI cli_link.go 逐字一致
BIN_DIR="${HOME}/.local/bin"                # 命令入口目录（与 GUI cli_link.go 同一处）
LINK="${BIN_DIR}/nbskills"

RED=$'\033[31m'; GREEN=$'\033[32m'; YELLOW=$'\033[33m'; CYAN=$'\033[36m'; RESET=$'\033[0m'
info() { echo "${CYAN}▶${RESET} $*"; }
ok()   { echo "${GREEN}✓${RESET} $*"; }
warn() { echo "${YELLOW}⚠${RESET} $*"; }
err()  { echo "${RED}✗${RESET} $*" >&2; }

# usage 内嵌帮助（不读 $0：管道执行 curl|bash 时 $0 是 bash，读不到脚本本体）
usage() {
  cat <<'EOF'
install.sh - macOS / Linux 一键安装 nbskills 原生 CLI

用法:
  curl -fsSL https://jps-cli.devtestapp.com/nbskills/install.sh | bash
  curl -fsSL .../install.sh | bash -s -- [选项]

选项:
  --version <ver>     指定版本（默认装 latest.json 指向的最新版）
  --base-url <url>    覆盖分发站基址
  --no-bootstrap      安装后不触发首次 bootstrap
  -h, --help          显示本帮助

环境变量: NBSKILLS_INSTALL_VERSION / NBSKILLS_INSTALL_BASE_URL
EOF
}

while [[ $# -gt 0 ]]; do
  case "$1" in
    --version) [[ $# -ge 2 ]] || { err "--version 需要一个值"; exit 2; }; VERSION="$2"; shift 2 ;;
    --version=*) VERSION="${1#*=}"; shift ;;
    --base-url) [[ $# -ge 2 ]] || { err "--base-url 需要一个值"; exit 2; }; BASE_URL="$2"; shift 2 ;;
    --base-url=*) BASE_URL="${1#*=}"; shift ;;
    --no-bootstrap) RUN_BOOTSTRAP=0; shift ;;
    -h|--help) usage; exit 0 ;;
    *) err "未知参数: $1"; exit 2 ;;
  esac
done

command -v curl >/dev/null 2>&1 || { err "需要 curl"; exit 1; }
BASE_URL="${BASE_URL%/}"

# --- 探测平台（arch 用 Go 命名：amd64/arm64，对齐 latest.json 的键与文件名） ---
case "$(uname -s)" in
  Darwin) OS=darwin ;;
  Linux)  OS=linux ;;
  *) err "不支持的系统: $(uname -s)（本脚本仅支持 macOS/Linux，Windows 用 install.ps1）"; exit 1 ;;
esac
case "$(uname -m)" in
  x86_64|amd64) ARCH=amd64 ;;
  arm64|aarch64) ARCH=arm64 ;;
  *) err "不支持的架构: $(uname -m)"; exit 1 ;;
esac
KEY="${OS}_${ARCH}"
BIN_NAME="nbskills_${KEY}"
info "平台: ${OS}/${ARCH}"

# --- 解析版本 ---
# 注意各处 sed/grep 都以 `|| true` 收尾：无匹配时它们返回非 0，配合 set -euo pipefail
# 会误杀脚本（尤其 --version 指定、服务端 latest.json 暂不可用时）。
LATEST_JSON="$(curl -fsSL "${BASE_URL}/latest.json" 2>/dev/null || true)"
LATEST_VERSION="$(printf '%s\n' "${LATEST_JSON}" | sed -n 's/.*"version": *"\([^"]*\)".*/\1/p' | head -1 || true)"
if [[ -z "${VERSION}" ]]; then
  [[ -z "${LATEST_VERSION}" ]] && { err "无法从 ${BASE_URL}/latest.json 解析版本，请用 --version 指定"; exit 1; }
  VERSION="${LATEST_VERSION}"
fi
info "安装版本: ${VERSION}"

# VERSION 会拼进 URL、安装路径、文件名——严格 SemVer 校验，防路径穿越 / 注入。
if ! [[ "${VERSION}" =~ ^[0-9]+\.[0-9]+\.[0-9]+([-+][0-9A-Za-z.-]+)?$ ]]; then
  err "版本号非法（需 SemVer）: ${VERSION}"; exit 2
fi

# --- 取该版本的 sha256（每版本 manifest release.json 优先，root latest.json 兜底） ---
# 每版本 manifest 让任意 pin 版本也能校验，而不是只有 latest 能校验。
MANIFEST="$(curl -fsSL "${BASE_URL}/${VERSION}/release.json" 2>/dev/null || true)"
[[ -z "${MANIFEST}" && "${VERSION}" == "${LATEST_VERSION}" ]] && MANIFEST="${LATEST_JSON}"
EXPECTED_SHA="$(printf '%s\n' "${MANIFEST}" | grep "\"${KEY}\":" 2>/dev/null | sed -n 's/.*"sha256": *"\([^"]*\)".*/\1/p' | head -1 || true)"
[[ -z "${EXPECTED_SHA}" ]] && warn "未取到 ${VERSION}/${KEY} 的 sha256（无 manifest），跳过完整性校验（传输由 HTTPS 保护）"

# --- 下载二进制 ---
URL="${BASE_URL}/${VERSION}/${BIN_NAME}"
TMP="$(mktemp -d)"; trap 'rm -rf "${TMP}"' EXIT
info "下载 ${URL}"
curl -fSL --progress-bar "${URL}" -o "${TMP}/${BIN_NAME}" || { err "下载失败: ${URL}"; exit 1; }

# --- 校验 sha256 ---
if [[ -n "${EXPECTED_SHA}" ]]; then
  if command -v sha256sum >/dev/null 2>&1; then GOT="$(sha256sum "${TMP}/${BIN_NAME}" | awk '{print $1}')";
  elif command -v shasum >/dev/null 2>&1; then GOT="$(shasum -a 256 "${TMP}/${BIN_NAME}" | awk '{print $1}')";
  else GOT=""; warn "无 sha256 工具，跳过校验"; fi
  if [[ -n "${GOT}" && "${GOT}" != "${EXPECTED_SHA}" ]]; then
    err "sha256 校验失败：期望 ${EXPECTED_SHA}，实际 ${GOT}"; exit 1
  fi
  [[ -n "${GOT}" ]] && ok "sha256 校验通过"
fi

# --- 就位到 versions 目录 ---
VER_DIR="${HOME}/.local/share/nbskills/versions/${VERSION}"
DEST="${VER_DIR}/nbskills"
mkdir -p "${VER_DIR}"
mv "${TMP}/${BIN_NAME}" "${DEST}"
chmod 755 "${DEST}"
ok "二进制已就位: ${DEST}"

# --- 入口软链 ~/.local/bin/nbskills（与 GUI 链接命令行同一目录） ---
mkdir -p "${BIN_DIR}"
[[ -e "${LINK}" || -L "${LINK}" ]] && rm -f "${LINK}"
ln -s "${DEST}" "${LINK}"
ok "命令入口: ${LINK} -> ${DEST}"

# --- PATH（幂等，带共享标记，让 GUI 与安装脚本互相识别） ---
path_has() { case ":${PATH}:" in *":${1}:"*) return 0 ;; *) return 1 ;; esac; }
SOURCE_HINT=""   # 非空表示需用户刷新 profile，值为精确的 source 命令
if path_has "${BIN_DIR}"; then
  ok "${BIN_DIR} 已在 PATH"
else
  LINE=$'\n'"${RC_MARKER}"$'\n'"export PATH=\"${BIN_DIR}:\$PATH\""$'\n'
  WROTE=""
  for rc in "${HOME}/.zshrc" "${HOME}/.bashrc" "${HOME}/.profile"; do
    [[ -f "${rc}" ]] && grep -qF "${RC_MARKER}" "${rc}" 2>/dev/null && continue
    printf '%s' "${LINE}" >> "${rc}" 2>/dev/null && WROTE="${WROTE} ${rc}" || true
  done
  # 按当前登录 shell 给出精确的 source 目标（$SHELL 优先，回落 .profile）
  case "${SHELL##*/}" in
    zsh)  PRIMARY_RC="${HOME}/.zshrc" ;;
    bash) PRIMARY_RC="${HOME}/.bashrc" ;;
    *)    PRIMARY_RC="${HOME}/.profile" ;;
  esac
  if [[ -n "${WROTE}" ]]; then
    warn "${BIN_DIR} 不在当前 PATH，已写入:${WROTE}"
    SOURCE_HINT="source ${PRIMARY_RC}"
  else
    warn "${BIN_DIR} 不在 PATH 且无法写入 shell 配置，请手动加: export PATH=\"${BIN_DIR}:\$PATH\""
  fi
fi

# --- 自检 + 首次 bootstrap（配置索引 + 装 nbskills skill），best-effort，不阻断 ---
"${DEST}" --version >/dev/null 2>&1 || { err "安装的二进制无法运行: ${DEST}"; exit 1; }
if [[ "${RUN_BOOTSTRAP}" -eq 1 && -z "${CI:-}" ]]; then
  info "触发首次 bootstrap…"
  NBSKILLS_FORCE_CLI=1 NBSKILLS_NO_UPDATE=1 "${DEST}" __bootstrap >/dev/null 2>&1 || warn "bootstrap 失败(不阻断安装)"
fi

# --- 同步已运行的常驻服务到新版本（web 自升级场景）---
# 仅当 daemon 已安装且 IPC 在线才重启；未装/未运行则幂等跳过。
NBSKILLS_FORCE_CLI=1 NBSKILLS_NO_UPDATE=1 "${DEST}" daemon restart-if-outdated --non-interactive >/dev/null 2>&1 || true

echo ""
ok "nbskills $("${DEST}" --version 2>/dev/null || echo "${VERSION}") 安装完成"
if [[ -n "${SOURCE_HINT}" ]]; then
  echo "   让当前终端立即生效: ${CYAN}${SOURCE_HINT}${RESET}   （或重开一个终端）"
fi
echo "   验证: ${CYAN}nbskills --version${RESET} / ${CYAN}nbskills doctor${RESET}"
