#!/usr/bin/env bash
set -euo pipefail

# npm package name (product CLI remains `clavue`; package is `iclavue` after
# the public clavue name was security-held on the registry).
PACKAGE="${CLAVUE_PACKAGE:-iclavue}"
VERSION_INPUT="${1:-${CLAVUE_VERSION:-latest}}"

need_cmd() {
  if ! command -v "$1" >/dev/null 2>&1; then
    printf 'Missing required command: %s\n' "$1" >&2
    exit 1
  fi
}

check_node() {
  need_cmd node

  local node_major
  node_major="$(node -p "process.versions.node.split('.')[0]")"
  if [[ -z "$node_major" || "$node_major" -lt 18 ]]; then
    printf 'clavue requires Node.js 18 or newer. Found: %s\n' "$(node -v)" >&2
    exit 1
  fi
}

resolve_version() {
  if [[ "$VERSION_INPUT" != "latest" ]]; then
    printf '%s' "${VERSION_INPUT#v}"
    return 0
  fi

  npm view "$PACKAGE" version
}

# npm's global install does an atomic rename of the existing package
# directory into a `.<name>-<rand>` staging directory before unpacking the
# new version. On macOS APFS AND Linux ext4 this fails with ENOTEMPTY when
# the previous install left over files (interrupted install, leftover
# symlink target, leftover staging dir from a prior failed run). Once a
# staging dir survives, EVERY future `npm install -g clavue` on that host
# fails at the same path until the leftover is removed. Clean leftovers
# first so the next `npm install -g` can rename without conflict.
clean_global_residue() {
  local remove_live_package="${1:-0}"
  local prefix
  prefix="$(npm prefix -g 2>/dev/null || true)"
  if [[ -z "$prefix" ]]; then
    return 0
  fi

  local node_modules="${prefix}/lib/node_modules"
  # Linux/macOS layout uses lib/node_modules; some distros use just
  # node_modules under prefix. Try both.
  if [[ ! -d "$node_modules" ]]; then
    if [[ -d "${prefix}/node_modules" ]]; then
      node_modules="${prefix}/node_modules"
    else
      return 0
    fi
  fi

  local pkg_dir="${node_modules}/${PACKAGE}"
  local bin_link="${prefix}/bin/${PACKAGE}"
  local needs_sudo=0
  local has_residue=0
  if [[ "$remove_live_package" -eq 1 && -e "$pkg_dir" ]]; then
    has_residue=1
  fi
  if [[ -n "$(compgen -G "${node_modules}/.${PACKAGE}-*" || true)" ]]; then
    has_residue=1
  fi
  # Also catch dangling bin symlinks (pointing into a removed staging dir).
  if [[ -L "$bin_link" && ! -e "$bin_link" ]]; then
    has_residue=1
  fi
  if [[ "$has_residue" -eq 0 ]]; then
    return 0
  fi
  if [[ ! -w "$node_modules" ]]; then
    needs_sudo=1
  fi

  printf 'Cleaning leftover %s install in %s...\n' "$PACKAGE" "$node_modules"
  local live_target=()
  if [[ "$remove_live_package" -eq 1 ]]; then
    live_target=("$pkg_dir")
  fi
  if [[ "$needs_sudo" -eq 1 ]]; then
    sudo rm -rf "${live_target[@]}" "${node_modules}"/."${PACKAGE}"-* 2>/dev/null || true
    if [[ -L "$bin_link" && ! -e "$bin_link" ]]; then
      sudo rm -f "$bin_link" 2>/dev/null || true
    fi
  else
    rm -rf "${live_target[@]}" "${node_modules}"/."${PACKAGE}"-* 2>/dev/null || true
    if [[ -L "$bin_link" && ! -e "$bin_link" ]]; then
      rm -f "$bin_link" 2>/dev/null || true
    fi
  fi
}

main() {
  need_cmd npm
  check_node

  local version
  version="$(resolve_version)"
  if [[ -z "$version" ]]; then
    printf 'Unable to determine the latest %s version from npm.\n' "$PACKAGE" >&2
    exit 1
  fi

  printf 'Installing %s@%s globally from npm...\n' "$PACKAGE" "$version"
  printf 'For one-shot use without a global install, run: npx -y %s@%s\n' "$PACKAGE" "$version"
  clean_global_residue
  if ! npm install -g "${PACKAGE}@${version}"; then
    printf '\nnpm install failed. Retrying once after a deeper cleanup...\n' >&2
    clean_global_residue 1
    npm install -g "${PACKAGE}@${version}"
  fi

  printf 'Installed %s@%s globally\n' "$PACKAGE" "$version"
  printf 'Available commands after npm install: clavue  (alias: iclavue)\n'
  clavue --version || iclavue --version || true

  printf '\nNext step:\n'
  printf '  Run: clavue\n'
  printf '  First launch opens API setup. Choose "自定义 API 配置" when you have an API URL and API key or Auth Token ready; then choose a model family and add a profile.\n'
  printf '  After saving, answer "no" at "返回主菜单？" to enter Clavue immediately with the default profile.\n'
  printf '  If setup is wrong or skipped, reopen it any time with: clavue provider\n'
}

main "$@"
