#!/usr/bin/env sh
# install.sh - Public svdo CLI installer for https://packages.svdo.ai/install.sh.
set -eu

DEFAULT_PACKAGE_SPEC="https://packages.svdo.ai/desktop-local/production/current.tgz"
PACKAGE_SPEC=${SVDO_PACKAGE:-$DEFAULT_PACKAGE_SPEC}
TELEMETRY_URL="https://api.svdo.ai/install-events"
install_id=
platform_os=
platform_arch=

info() {
  printf '%s\n' "$*"
}

fail() {
  info "ERROR: $1" >&2
  shift || true
  if [ "$#" -gt 0 ]; then
    info "" >&2
    info "Next steps:" >&2
    for step in "$@"; do
      info "  - $step" >&2
    done
  fi
  exit 1
}

command_exists() {
  command -v "$1" >/dev/null 2>&1
}

valid_install_id() {
  printf '%s' "$1" | grep -Eq '^inst_[A-Za-z0-9_-]{24,96}$'
}

sanitize_telemetry_value() {
  printf '%s' "$1" | LC_ALL=C tr -c 'A-Za-z0-9._:@/+ -' '_' | cut -c 1-128
}

telemetry_enabled() {
  [ "${SVDO_TELEMETRY:-1}" != "0" ] && command_exists curl
}

extract_install_id() {
  response=$1
  candidate=
  case "$response" in
    inst_*) candidate=$response ;;
    *)
      candidate=$(printf '%s' "$response" | sed -n 's/.*"install_id"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | sed -n '1p')
      ;;
  esac

  if [ -n "$candidate" ] && valid_install_id "$candidate"; then
    printf '%s\n' "$candidate"
  fi
}

telemetry_start() {
  if ! telemetry_enabled; then
    return 0
  fi

  payload=$(printf '{"os":"%s","arch":"%s","channel":"production"}' \
    "$(sanitize_telemetry_value "$platform_os")" \
    "$(sanitize_telemetry_value "$platform_arch")")

  response=$(curl -fsS \
    --connect-timeout 2 \
    --max-time 3 \
    -H 'content-type: application/json' \
    -X POST \
    -d "$payload" \
    "$TELEMETRY_URL/start" 2>/dev/null || true)

  install_id=$(extract_install_id "$response" || true)
}

telemetry_complete() {
  if ! telemetry_enabled || ! valid_install_id "$install_id"; then
    return 0
  fi

  version=$(svdo --version 2>/dev/null | sed -n '/./{p;q;}' || true)
  if [ -n "$version" ]; then
    payload=$(printf '{"version":"%s"}' "$(sanitize_telemetry_value "$version")")
  else
    payload='{}'
  fi

  curl -fsS \
    --connect-timeout 2 \
    --max-time 3 \
    -H 'content-type: application/json' \
    -X POST \
    -d "$payload" \
    "$TELEMETRY_URL/$install_id/complete" >/dev/null 2>&1 || true
}

persist_install_id() {
  if ! valid_install_id "$install_id"; then
    return 0
  fi

  case "$platform_os" in
    Darwin)
      install_id_dir="$HOME/Library/Application Support/SVDO"
      ;;
    *)
      install_id_dir="${XDG_DATA_HOME:-$HOME/.local/share}/svdo"
      ;;
  esac

  mkdir -p "$install_id_dir" 2>/dev/null &&
    printf '%s\n' "$install_id" > "$install_id_dir/install-id" 2>/dev/null || true
}

detect_platform() {
  os=$(uname -s 2>/dev/null || printf unknown)
  arch=$(uname -m 2>/dev/null || printf unknown)
  platform_os=$os
  platform_arch=$arch

  case "$os" in
    Darwin|Linux) ;;
    *)
      fail "Unsupported operating system: $os" \
        "Run this installer on macOS or Linux." \
        "Use npm install -g $PACKAGE_SPEC manually if your platform supports the package."
      ;;
  esac

  case "$arch" in
    x86_64|amd64|arm64|aarch64) ;;
    *)
      fail "Unsupported CPU architecture: $arch" \
        "Use a 64-bit Intel/AMD or ARM macOS/Linux environment." \
        "Use npm install -g $PACKAGE_SPEC manually if your platform supports the package."
      ;;
  esac
}

global_bin_from_npm() {
  if npm bin -g >/dev/null 2>&1; then
    npm bin -g 2>/dev/null
    return
  fi

  prefix=$(npm config get prefix 2>/dev/null || true)
  if [ -n "$prefix" ]; then
    printf '%s/bin\n' "$prefix"
  fi
}

global_bin_from_bun() {
  bun pm bin -g 2>/dev/null || true
}

installer_name=
global_bin=
downloaded_package=

select_installer() {
  if command_exists npm; then
    installer_name=npm
    global_bin=$(global_bin_from_npm)
    return
  fi

  if command_exists bun; then
    installer_name=bun
    global_bin=$(global_bin_from_bun)
    return
  fi

  fail "Neither npm nor bun was found on PATH." \
    "Install Node.js 24 or newer, which includes npm: https://nodejs.org/" \
    "Or install Bun, then rerun this installer: https://bun.sh/"
}

install_package() {
  install_spec=$PACKAGE_SPEC
  case "$PACKAGE_SPEC" in
    http://*|https://*)
      command_exists curl || fail "curl is required to download $PACKAGE_SPEC." \
        "Install curl, or set SVDO_PACKAGE to a local tarball path."
      downloaded_package=$(mktemp "${TMPDIR:-/tmp}/svdo-package.XXXXXX.tgz")
      info "Downloading svdo package..."
      curl -fsSL \
        --connect-timeout 10 \
        --max-time 120 \
        -o "$downloaded_package" \
        "$PACKAGE_SPEC"
      install_spec=$downloaded_package
      ;;
  esac

  case "$installer_name" in
    npm)
      info "Using npm to install svdo globally..."
      info "npm may print deprecated-package warnings for transitive native/runtime dependencies."
      info "Those warnings are non-fatal unless npm exits with an installation error."
      npm install -g "$install_spec"
      ;;
    bun)
      info "Using bun to install svdo globally..."
      bun add -g "$install_spec"
      ;;
    *)
      fail "No supported package installer was selected." \
        "Install Node.js/npm or Bun, then rerun this installer."
      ;;
  esac
}

cleanup_downloaded_package() {
  if [ -n "$downloaded_package" ] && [ -f "$downloaded_package" ]; then
    rm -f "$downloaded_package" || true
  fi
}

show_existing_joule() {
  if command_exists joule; then
    existing_path=$(command -v joule)
    existing_info=$(joule --version 2>/dev/null || svdo --help 2>/dev/null | sed -n '/./{p;q;}' || true)
    if [ -z "$existing_info" ]; then
      existing_info="version unknown"
    fi
    info "Existing joule command found:"
    info "  path: $existing_path"
    info "  info: $existing_info"
    info "The installer will update or reuse this command through the selected package manager."
    info ""
  fi
}

verify_joule() {
  PATH="$HOME/.local/bin:$HOME/bin:/usr/local/bin${global_bin:+:$global_bin}:$PATH"
  export PATH

  info ""
  info "Verifying svdo --help..."
  if command_exists svdo && svdo --help >/dev/null 2>&1; then
    telemetry_complete
    persist_install_id
    info "svdo installed successfully."
    info ""
    info "Next steps:"
    info "  svdo start"
    info "  svdo init"
    info "  svdo open"
    exit 0
  fi

  if [ -n "$global_bin" ]; then
    fail "svdo was installed, but 'svdo --help' could not be verified in this shell." \
      "Add this global bin directory to PATH: $global_bin" \
      "Open a new terminal or reload your shell profile." \
      "Run: svdo --help"
  fi

  fail "svdo was installed, but 'svdo --help' could not be verified in this shell." \
    "Add your package manager's global bin directory to PATH." \
    "Open a new terminal or reload your shell profile." \
    "Run: svdo --help"
}

main() {
  trap cleanup_downloaded_package EXIT INT TERM
  info "=== svdo CLI installer ==="
  info ""

  detect_platform
  telemetry_start
  show_existing_joule
  select_installer

  if ! install_package; then
    cleanup_downloaded_package
    fail "Global installation failed with $installer_name." \
      "Check that your $installer_name global package directory is writable." \
      "Retry with a user-level package manager setup." \
      "If this was a permissions error, avoid sudo unless your package manager documentation requires it."
  fi
  cleanup_downloaded_package

  verify_joule
}

if [ "${SVDO_INSTALLER_SOURCE_ONLY:-0}" != "1" ]; then
  main "$@"
fi
