#!/usr/bin/env bash
# Oracle public installer — hosted/default stays prepare-only.
#
#   curl -fsSL https://oracle.demi.la/install.sh | bash
#   curl -fsSL https://oracle.demi.la/install.sh | bash -s -- --version latest
#   curl -fsSL https://oracle.demi.la/install.sh | bash -s -- --prefix "$HOME/.local"
#
# What this does:
#   - installs @oracle-agent/oracle into a user prefix (no root, no global npm -g)
#   - puts `oracle` on PATH via ~/.local/bin (or --prefix/bin)
#   - never asks for keys, seeds, or wallet approval
#
# What this installer never does:
#   - sign or broadcast transactions
#   - start a signer or import a key
#   - never starts an external agent runtime
# An explicit later `oracle signer` setup is a separate operator step.
set -euo pipefail

ORACLE_INSTALL_VERSION="${ORACLE_INSTALL_VERSION:-latest}"
ORACLE_INSTALL_PREFIX="${ORACLE_INSTALL_PREFIX:-}"
ORACLE_INSTALL_FORCE_NODE="${ORACLE_INSTALL_FORCE_NODE:-0}"
ORACLE_NPM_PACKAGE="${ORACLE_NPM_PACKAGE:-@oracle-agent/oracle}"
MIN_NODE_MAJOR=20
MIN_NODE_MINOR=19
NONINTERACTIVE=1
DO_SETUP=0
DO_DOCTOR=1
PRINT_ONLY=0

log()  { printf 'oracle-install: %s\n' "$*"; }
err()  { printf 'oracle-install: ERROR: %s\n' "$*" >&2; }
die()  { err "$*"; exit 1; }
have() { command -v "$1" >/dev/null 2>&1; }

# Mirror packages/oracle/src/tui/brand.mjs SPLASH_ORB_FRAMES. Hardcoded because
# this script runs before the package exists on disk.
want_globe() {
  [ -t 1 ] && [ "${TERM:-}" != "dumb" ] && [ -z "${NO_COLOR:-}" ] && [ "${ORACLE_INSTALL_PLAIN:-0}" != 1 ]
}

print_globe_frame() {
  local n="${1:-0}"
  local status="${2:-installing}"
  case "$n" in
    1)
      cat <<EOF
   ▓███▓      oracle
  ▒▓▓█████     ${status}
 ▒▒▓▓██████
  ░▒▒▓▓▓▓▓
   ░░▒▒▒▒
EOF
      ;;
    2)
      cat <<EOF
   ▓▓███      oracle
  ▒▓▓▓████     ${status}
 ▒▒▓▓▓█████
  ░▒▒▒▓▓▓▓
   ░░░▒▒▒
EOF
      ;;
    3)
      cat <<EOF
   ░▒▒▓▓      oracle
  ░▒▒▓▓▓▓▓     ${status}
 ░░▒▒▓▓████
  ▓▓▓██████
   █████▓
EOF
      ;;
    *)
      cat <<EOF
   ███▓▓      oracle
  █████▓▓▒     ${status}
 ██████▓▓▒▒
  ▓▓▓▓▒▒▒░
   ▒▒▒░░░
EOF
      ;;
  esac
}

print_globe() {
  want_globe || return 0
  printf '\n'
  print_globe_frame 0 "installing"
  printf '\n'
}

animate_while() {
  local status="$1"
  shift
  if ! want_globe; then
    "$@"
    return $?
  fi
  local log rc pid i
  log="$(mktemp)"
  "$@" >"$log" 2>&1 &
  pid=$!
  i=0
  printf '\033[?25l' || true
  printf '\n'
  print_globe_frame 0 "$status"
  while kill -0 "$pid" 2>/dev/null; do
    sleep 0.12
    printf '\033[5A'
    print_globe_frame "$((i % 4))" "$status"
    i=$((i + 1))
  done
  set +e
  wait "$pid"
  rc=$?
  set -e
  printf '\033[5A'
  print_globe_frame 0 "ready"
  printf '\n\033[?25h' || true
  if [ "$rc" -ne 0 ]; then
    cat "$log" >&2
  fi
  rm -f "$log"
  return "$rc"
}

usage() {
  cat <<'EOF'
Oracle install (curl)

  curl -fsSL https://oracle.demi.la/install.sh | bash
  curl -fsSL https://oracle.demi.la/install.sh | bash -s -- [options]

Options:
  --version <ver|latest>   Package version (default: latest)
  --prefix <dir>           Install root (default: ~/.local)
  --home <dir>             Package home (default: ~/.local/share/oracle)
  --no-doctor              Skip post-install doctor
  --setup                  Run `oracle setup model` after install (interactive)
  --print                  Print plan only
  -h, --help               Show help

Env:
  ORACLE_INSTALL_VERSION   same as --version
  ORACLE_INSTALL_PREFIX    same as --prefix
  ORACLE_HOME              package data dir override
  npm_config_registry      custom npm registry
EOF
}

while [ $# -gt 0 ]; do
  case "$1" in
    --version) ORACLE_INSTALL_VERSION="${2:-}"; shift 2 ;;
    --prefix)  ORACLE_INSTALL_PREFIX="${2:-}"; shift 2 ;;
    --home)    ORACLE_HOME_OVERRIDE="${2:-}"; shift 2 ;;
    --no-doctor) DO_DOCTOR=0; shift ;;
    --setup) DO_SETUP=1; shift ;;
    --print) PRINT_ONLY=1; shift ;;
    -h|--help) usage; exit 0 ;;
    *) die "unknown arg: $1 (see --help)" ;;
  esac
done

# --- platform ---------------------------------------------------------------
OS="$(uname -s 2>/dev/null || echo unknown)"
ARCH="$(uname -m 2>/dev/null || echo unknown)"
case "$OS" in
  Linux|Darwin) ;;
  MINGW*|MSYS*|CYGWIN*)
    die "Windows: iex (irm https://oracle.demi.la/install.ps1)  — installs the Oracle app. CLI: npm i -g @oracle-agent/oracle"
    ;;
  *) die "unsupported OS: $OS" ;;
esac

PREFIX="${ORACLE_INSTALL_PREFIX:-$HOME/.local}"
BIN_DIR="${PREFIX}/bin"
SHARE_DIR="${ORACLE_HOME_OVERRIDE:-${ORACLE_HOME:-$HOME/.local/share/oracle}}"
PKG_DIR="${SHARE_DIR}/package"

need_cmds() {
  for c in curl tar mkdir ln chmod; do
    have "$c" || die "missing required command: $c"
  done
}

node_ok() {
  have node || return 1
  # node -p 'process.versions.node'
  local ver major minor
  ver="$(node -p 'process.versions.node' 2>/dev/null || true)"
  [ -n "$ver" ] || return 1
  major="${ver%%.*}"
  minor="${ver#*.}"; minor="${minor%%.*}"
  if [ "$major" -gt "$MIN_NODE_MAJOR" ]; then return 0; fi
  if [ "$major" -eq "$MIN_NODE_MAJOR" ] && [ "${minor:-0}" -ge "$MIN_NODE_MINOR" ]; then return 0; fi
  return 1
}

ensure_node() {
  if node_ok; then
    log "node $(node -p 'process.versions.node') OK"
    return 0
  fi
  if have node; then
    err "node $(node -p 'process.versions.node' 2>/dev/null || echo '?') is too old (need >= ${MIN_NODE_MAJOR}.${MIN_NODE_MINOR})"
  else
    err "node not found (need >= ${MIN_NODE_MAJOR}.${MIN_NODE_MINOR})"
  fi

  # Best-effort: nvm if already present
  if [ -s "$HOME/.nvm/nvm.sh" ]; then
    # shellcheck disable=SC1091
    . "$HOME/.nvm/nvm.sh"
    log "trying nvm install ${MIN_NODE_MAJOR}"
    nvm install "$MIN_NODE_MAJOR" >/dev/null
    nvm use "$MIN_NODE_MAJOR" >/dev/null
    node_ok && { log "node $(node -p 'process.versions.node') via nvm"; return 0; }
  fi

  cat >&2 <<EOF
oracle-install: install Node.js ${MIN_NODE_MAJOR}.${MIN_NODE_MINOR}+ then re-run:

  # macOS (Homebrew)
  brew install node@${MIN_NODE_MAJOR}

  # Ubuntu/Debian
  curl -fsSL https://deb.nodesource.com/setup_${MIN_NODE_MAJOR}.x | sudo -E bash -
  sudo apt-get install -y nodejs

  # or nvm
  curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
  nvm install ${MIN_NODE_MAJOR}

Then:
  curl -fsSL https://oracle.demi.la/install.sh | bash
EOF
  exit 1
}

ensure_npm() {
  have npm || die "npm not found (ships with Node). Reinstall Node ${MIN_NODE_MAJOR}+."
  log "npm $(npm -v 2>/dev/null || echo '?')"
}

resolve_version() {
  local want="$ORACLE_INSTALL_VERSION"
  if [ "$want" = "latest" ] || [ -z "$want" ]; then
    want="$(npm view "$ORACLE_NPM_PACKAGE" version --prefer-online 2>/dev/null || true)"
    [ -n "$want" ] || die "could not resolve latest version of $ORACLE_NPM_PACKAGE (network/npm?)"
  fi
  ORACLE_RESOLVED_VERSION="$want"
  log "target ${ORACLE_NPM_PACKAGE}@${ORACLE_RESOLVED_VERSION}"
}

install_package() {
  mkdir -p "$PKG_DIR" "$BIN_DIR" "$SHARE_DIR"
  # Isolated prefix install — no sudo, no global pollution
  cat >"$PKG_DIR/package.json" <<EOF
{
  "name": "oracle-user-install",
  "private": true,
  "description": "Oracle curl-install root (do not publish)"
}
EOF
  log "installing into $PKG_DIR"
  (
    cd "$PKG_DIR"
    npm install "${ORACLE_NPM_PACKAGE}@${ORACLE_RESOLVED_VERSION}" \
      --no-fund \
      --no-audit \
      --prefer-online \
      --loglevel=error
  )

  local oracle_bin=""
  if [ -x "$PKG_DIR/node_modules/.bin/oracle" ]; then
    oracle_bin="$PKG_DIR/node_modules/.bin/oracle"
  elif [ -f "$PKG_DIR/node_modules/@oracle-agent/oracle/dist/bin/oracle.mjs" ]; then
    oracle_bin="$PKG_DIR/node_modules/@oracle-agent/oracle/dist/bin/oracle.mjs"
  else
    die "install finished but oracle binary missing under $PKG_DIR"
  fi

  # Stable launcher in BIN_DIR
  cat >"$BIN_DIR/oracle" <<EOF
#!/usr/bin/env bash
# Generated by oracle.demi.la/install.sh — do not edit; re-run installer to upgrade.
set -euo pipefail
export ORACLE_INSTALL_ROOT="$PKG_DIR"
exec "$oracle_bin" "\$@"
EOF
  chmod 755 "$BIN_DIR/oracle"

  # Convenience: also expose oracle-data-mcp if present
  if [ -x "$PKG_DIR/node_modules/.bin/oracle-data-mcp" ]; then
    cat >"$BIN_DIR/oracle-data-mcp" <<EOF
#!/usr/bin/env bash
set -euo pipefail
exec "$PKG_DIR/node_modules/.bin/oracle-data-mcp" "\$@"
EOF
    chmod 755 "$BIN_DIR/oracle-data-mcp"
  fi

  # Record install metadata
  cat >"$SHARE_DIR/install.json" <<EOF
{
  "package": "${ORACLE_NPM_PACKAGE}",
  "version": "${ORACLE_RESOLVED_VERSION}",
  "prefix": "${PREFIX}",
  "bin": "${BIN_DIR}/oracle",
  "home": "${PKG_DIR}",
  "installedAt": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
  "method": "curl-install.sh"
}
EOF
}

path_hint() {
  case ":$PATH:" in
    *":$BIN_DIR:"*) return 0 ;;
  esac
  cat <<EOF

Add Oracle to your PATH (one-time):

  # bash
  echo 'export PATH="$BIN_DIR:\$PATH"' >> ~/.bashrc && source ~/.bashrc

  # zsh
  echo 'export PATH="$BIN_DIR:\$PATH"' >> ~/.zshrc && source ~/.zshrc

  # fish
  fish_add_path $BIN_DIR
EOF
}

verify() {
  export PATH="$BIN_DIR:$PATH"
  hash -r 2>/dev/null || true
  if ! have oracle; then
    die "oracle not on PATH after install. Expected $BIN_DIR/oracle"
  fi
  local ver
  ver="$(oracle --version 2>/dev/null | head -1 || true)"
  log "installed: ${ver:-oracle (version unknown)}"
  if [ "$DO_DOCTOR" = 1 ]; then
    oracle doctor 2>/dev/null | head -20 || true
  fi
}

print_next() {
  cat <<EOF

Oracle ready.

  oracle

That command opens sign-in: Claude, Codex, Grok, or an API key
(OpenRouter, DeepSeek, Nous, and the rest).

Upgrade later:
  curl -fsSL https://oracle.demi.la/install.sh | bash

Install root: $PKG_DIR
Binary:       $BIN_DIR/oracle
EOF
  if [ "$(uname -s)" = Darwin ]; then
    cat <<'EOF'

macOS desktop (unsigned beta):
  if the app is installed:  xattr -cr /Applications/Oracle.app && open /Applications/Oracle.app
  if macOS blocks it:       right-click Oracle.app → Open (once)

Chrome side panel:
  Load unpacked from the Oracle repo apps/oracle-extension/dist after npm run ext:dev
  then: npm run ext:install-host
EOF
  fi
  path_hint
}

main() {
  print_globe
  need_cmds
  log "os=$OS arch=$ARCH"
  log "prefix=$PREFIX home=$SHARE_DIR"
  if [ "$PRINT_ONLY" = 1 ]; then
    resolve_version
    log "would install ${ORACLE_NPM_PACKAGE}@${ORACLE_RESOLVED_VERSION} → $PKG_DIR"
    exit 0
  fi
  ensure_node
  ensure_npm
  resolve_version
  animate_while installing install_package
  verify
  if [ "$DO_SETUP" = 1 ]; then
    export PATH="$BIN_DIR:$PATH"
    oracle setup model || true
  fi
  print_next
}

main
