#!/usr/bin/env bash
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# NemoClaw curl-pipe-bash installer.
#
# Usage:
#   curl -fsSL https://raw.githubusercontent.com/x402agent/NemoClaw/main/scripts/install.sh | bash

set -euo pipefail

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'

info()  { echo -e "${GREEN}[install]${NC} $1"; }
warn()  { echo -e "${YELLOW}[install]${NC} $1"; }
fail()  { echo -e "${RED}[install]${NC} $1"; exit 1; }

# Ensure nvm environment is loaded in the current shell.
ensure_nvm_loaded() {
  if [ -z "${NVM_DIR:-}" ]; then
    export NVM_DIR="$HOME/.nvm"
  fi
  if [ -s "$NVM_DIR/nvm.sh" ]; then
    # shellcheck source=/dev/null
    . "$NVM_DIR/nvm.sh"
  fi
}

# Refresh PATH so that npm global bin is discoverable.
refresh_path() {
  ensure_nvm_loaded

  local npm_bin
  npm_bin="$(npm config get prefix 2>/dev/null)/bin" || true
  if [ -n "$npm_bin" ] && [ -d "$npm_bin" ]; then
    case ":$PATH:" in
      *":$npm_bin:"*) ;;  # already on PATH
      *) export PATH="$npm_bin:$PATH" ;;
    esac
  fi
}

MIN_NODE_MAJOR=20
MIN_NPM_MAJOR=10
RECOMMENDED_NODE_MAJOR=22
RUNTIME_REQUIREMENT_MSG="NemoClaw requires Node.js >=${MIN_NODE_MAJOR} and npm >=${MIN_NPM_MAJOR} (recommended Node.js ${RECOMMENDED_NODE_MAJOR})."

OS="$(uname -s)"
ARCH="$(uname -m)"

case "$OS" in
  Darwin) OS_LABEL="macOS" ;;
  Linux)  OS_LABEL="Linux" ;;
  *)      fail "Unsupported OS: $OS" ;;
esac

case "$ARCH" in
  x86_64|amd64) ARCH_LABEL="x86_64" ;;
  aarch64|arm64) ARCH_LABEL="aarch64" ;;
  *)             fail "Unsupported architecture: $ARCH" ;;
esac

info "Detected $OS_LABEL ($ARCH_LABEL)"

# ── Detect Node.js version manager ──────────────────────────────

NODE_MGR="none"
NEED_RESHIM=false

if command -v asdf > /dev/null 2>&1 && asdf plugin list 2>/dev/null | grep -q nodejs; then
  NODE_MGR="asdf"
elif [ -n "${NVM_DIR:-}" ] && [ -s "${NVM_DIR}/nvm.sh" ]; then
  NODE_MGR="nvm"
elif [ -s "$HOME/.nvm/nvm.sh" ]; then
  export NVM_DIR="$HOME/.nvm"
  NODE_MGR="nvm"
elif command -v fnm > /dev/null 2>&1; then
  NODE_MGR="fnm"
elif command -v brew > /dev/null 2>&1 && [ "$OS" = "Darwin" ]; then
  NODE_MGR="brew"
elif [ "$OS" = "Linux" ]; then
  NODE_MGR="nodesource"
fi

info "Node.js manager: $NODE_MGR"

version_major() {
  printf '%s\n' "${1#v}" | cut -d. -f1
}

ensure_supported_runtime() {
  command -v node > /dev/null 2>&1 || fail "${RUNTIME_REQUIREMENT_MSG} Node.js was not found on PATH."
  command -v npm > /dev/null 2>&1 || fail "${RUNTIME_REQUIREMENT_MSG} npm was not found on PATH."

  local node_version npm_version node_major npm_major
  node_version="$(node -v 2>/dev/null || true)"
  npm_version="$(npm --version 2>/dev/null || true)"
  node_major="$(version_major "$node_version")"
  npm_major="$(version_major "$npm_version")"

  [[ "$node_major" =~ ^[0-9]+$ ]] || fail "Could not determine Node.js version from '${node_version}'. ${RUNTIME_REQUIREMENT_MSG}"
  [[ "$npm_major" =~ ^[0-9]+$ ]] || fail "Could not determine npm version from '${npm_version}'. ${RUNTIME_REQUIREMENT_MSG}"

  if (( node_major < MIN_NODE_MAJOR || npm_major < MIN_NPM_MAJOR )); then
    fail "Unsupported runtime detected: Node.js ${node_version:-unknown}, npm ${npm_version:-unknown}. ${RUNTIME_REQUIREMENT_MSG} Upgrade Node.js and rerun the installer."
  fi

  info "Runtime OK: Node.js ${node_version}, npm ${npm_version}"
}

# ── Install Node.js 22 if needed ────────────────────────────────

install_node() {
  local current_major=""
  if command -v node > /dev/null 2>&1; then
    current_major="$(node -v 2>/dev/null | sed 's/^v//' | cut -d. -f1)"
  fi

  if [ "$current_major" = "22" ]; then
    info "Node.js 22 already installed: $(node -v)"
    return 0
  fi

  info "Installing Node.js 22..."

  case "$NODE_MGR" in
    asdf)
      local latest_22
      latest_22="$(asdf list all nodejs 2>/dev/null | grep '^22\.' | tail -1)"
      [ -n "$latest_22" ] || fail "Could not find Node.js 22 in asdf"
      asdf install nodejs "$latest_22"
      asdf global nodejs "$latest_22"
      NEED_RESHIM=true
      ;;
    nvm)
      # shellcheck source=/dev/null
      . "${NVM_DIR}/nvm.sh"
      nvm install 22
      nvm use 22
      nvm alias default 22
      ;;
    fnm)
      fnm install 22
      fnm use 22
      fnm default 22
      ;;
    brew)
      brew install node@22
      brew link --overwrite node@22 2>/dev/null || true
      ;;
    nodesource)
      curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - > /dev/null 2>&1
      sudo apt-get install -y -qq nodejs > /dev/null 2>&1
      ;;
    none)
      fail "No Node.js version manager found. Install Node.js 22 manually, then re-run."
      ;;
  esac

  info "Node.js $(node -v) installed"
}

install_node
ensure_supported_runtime

# ── Install Docker ───────────────────────────────────────────────

install_docker() {
  if command -v docker > /dev/null 2>&1 && docker info > /dev/null 2>&1; then
    info "Docker already running"
    return 0
  fi

  if command -v docker > /dev/null 2>&1; then
    # Docker installed but not running
    if [ "$OS" = "Darwin" ]; then
      if command -v colima > /dev/null 2>&1; then
        info "Starting Colima..."
        colima start
        return 0
      fi
    fi
    fail "Docker is installed but not running. Please start Docker and re-run."
  fi

  info "Installing Docker..."

  case "$OS" in
    Darwin)
      if ! command -v brew > /dev/null 2>&1; then
        fail "Homebrew required to install Docker on macOS. Install from https://brew.sh"
      fi
      info "Installing Colima + Docker CLI via Homebrew..."
      brew install colima docker
      info "Starting Colima..."
      colima start
      ;;
    Linux)
      sudo apt-get update -qq > /dev/null 2>&1
      sudo apt-get install -y -qq docker.io > /dev/null 2>&1
      sudo usermod -aG docker "$(whoami)"
      info "Docker installed. You may need to log out and back in for group changes."
      ;;
  esac

  if ! docker info > /dev/null 2>&1; then
    fail "Docker installed but not running. Start Docker and re-run."
  fi

  info "Docker is running"
}

install_docker

# ── Install OpenShell CLI binary ─────────────────────────────────

install_openshell() {
  if command -v openshell > /dev/null 2>&1; then
    info "openshell already installed: $(openshell --version 2>&1 || echo 'unknown')"
    return 0
  fi

  info "Installing openshell CLI..."

  case "$OS" in
    Darwin)
      case "$ARCH_LABEL" in
        x86_64)  ASSET="openshell-x86_64-apple-darwin.tar.gz" ;;
        aarch64) ASSET="openshell-aarch64-apple-darwin.tar.gz" ;;
      esac
      ;;
    Linux)
      case "$ARCH_LABEL" in
        x86_64)  ASSET="openshell-x86_64-unknown-linux-musl.tar.gz" ;;
        aarch64) ASSET="openshell-aarch64-unknown-linux-musl.tar.gz" ;;
      esac
      ;;
  esac

  tmpdir="$(mktemp -d)"
  if command -v gh > /dev/null 2>&1; then
    GH_TOKEN="${GITHUB_TOKEN:-}" gh release download --repo NVIDIA/OpenShell \
      --pattern "$ASSET" --dir "$tmpdir"
  else
    # Fallback: curl latest release
    curl -fsSL "https://github.com/NVIDIA/OpenShell/releases/latest/download/$ASSET" \
      -o "$tmpdir/$ASSET"
  fi

  tar xzf "$tmpdir/$ASSET" -C "$tmpdir"

  if [ -w /usr/local/bin ]; then
    install -m 755 "$tmpdir/openshell" /usr/local/bin/openshell
  else
    sudo install -m 755 "$tmpdir/openshell" /usr/local/bin/openshell
  fi

  rm -rf "$tmpdir"
  info "openshell $(openshell --version 2>&1 || echo '') installed"
}

install_openshell

# ── Install NemoClaw CLI ─────────────────────────────────────────

NPM_PACKAGE="@mawdbotsonsolana/nemoclaw"
info "Installing ${NPM_PACKAGE}..."
if [ "$NODE_MGR" = "nodesource" ]; then
  sudo npm install -g "$NPM_PACKAGE"
else
  npm install -g "$NPM_PACKAGE"
fi

if [ "$NEED_RESHIM" = true ]; then
  info "Reshimming asdf..."
  asdf reshim nodejs
fi

refresh_path

# ── Verify ───────────────────────────────────────────────────────

if ! command -v nemoclaw > /dev/null 2>&1; then
  # Try refreshing PATH one more time
  refresh_path
fi

if ! command -v nemoclaw > /dev/null 2>&1; then
  npm_bin="$(npm config get prefix 2>/dev/null)/bin" || true
  if [ -n "$npm_bin" ] && [ -x "$npm_bin/nemoclaw" ]; then
    warn "nemoclaw installed at $npm_bin/nemoclaw but not on current PATH."
    warn ""
    warn "Add it to your shell profile:"
    warn "  echo 'export PATH=\"$npm_bin:\$PATH\"' >> ~/.bashrc"
    warn "  source ~/.bashrc"
    warn ""
    warn "Or for zsh:"
    warn "  echo 'export PATH=\"$npm_bin:\$PATH\"' >> ~/.zshrc"
    warn "  source ~/.zshrc"
  else
    fail "nemoclaw installation failed. Binary not found."
  fi
fi

echo ""
info "Installation complete!"
info "nemoclaw $(nemoclaw --version 2>/dev/null || echo 'v0.1.0') is ready."
echo ""
echo "  Run \`nemoclaw onboard\` to get started"
echo ""

# ── Post-install: shell reload instructions ──────────────────

if [ "$NODE_MGR" = "nvm" ] || [ "$NODE_MGR" = "fnm" ]; then
  profile="$HOME/.bashrc"
  if [ -n "${ZSH_VERSION:-}" ] || [ "$(basename "${SHELL:-}")" = "zsh" ]; then
    profile="$HOME/.zshrc"
  elif [ ! -f "$HOME/.bashrc" ] && [ -f "$HOME/.profile" ]; then
    profile="$HOME/.profile"
  fi
  echo "  ──────────────────────────────────────────────────"
  warn "Your current shell may not have the updated PATH."
  echo ""
  echo "  To use nemoclaw now, run:"
  echo ""
  echo "    source $profile"
  echo ""
  echo "  Or open a new terminal window."
  echo "  ──────────────────────────────────────────────────"
  echo ""
fi
