#!/usr/bin/env bash
# 
# Install mise https://github.com/jdx/mise
#
#
set -euo pipefail


#**********************************
# Constants
#**********************************
readonly miseInstallUrl="https://mise.run"
readonly miseBinDir="${MISE_BIN_DIR:-$HOME/.local/bin}"
readonly miseDataDir="${MISE_DATA_DIR:-${XDG_DATA_HOME:-$HOME/.local/share}/mise}"
readonly miseBin="$miseBinDir/mise"

# Versions for tools (can override with environment variables)
NODE_VERSION="${NODE_VERSION:-20}"
PYTHON_VERSION="${PYTHON_VERSION:-3.12}"
JAVA_VERSION="${JAVA_VERSION:-21}"

dryRun=false
verbose=false

#**********************************
# Help / Usage
#**********************************
showHelp() {
  cat <<EOF

Bootstrap Script for mise + common development languages

Usage:
  MISE_BIN_DIR=/custom/bin \\
  MISE_DATA_DIR=/custom/data \\
  NODE_VERSION=18 PYTHON_VERSION=3.11 JAVA_VERSION=17 \\
      $0 [OPTIONS]

Environment variables:
  MISE_BIN_DIR      Directory to install mise binary (default: $HOME/.local/bin)
  MISE_DATA_DIR     Directory for mise data (default: ${XDG_DATA_HOME:-$HOME/.local/share}/mise)
  NODE_VERSION      Node.js version to install (default: 20)
  PYTHON_VERSION    Python version to install (default: 3.12)
  JAVA_VERSION      Java version to install (default: 21)

Options:
  --help            Show this help message
  --dry-run         Show commands without executing
  --verbose         Show detailed debug output

Examples:
  # Default install with default versions
  $0

  # Custom directories and versions
  MISE_BIN_DIR=/opt/mise/bin \\
  MISE_DATA_DIR=/opt/mise/data \\
  NODE_VERSION=18 PYTHON_VERSION=3.11 JAVA_VERSION=17 \\
      $0

  # Dry-run mode
  $0 --dry-run

EOF
}

#**********************************
# Logging Functions
#**********************************
logInfo() { echo "[INFO] $1"; }
logDebug() { if [ "$verbose" = true ]; then echo "[DEBUG] $1"; fi; }
logSuccess() { echo "[SUCCESS] $1"; }
logError() { echo "[ERROR] $1" >&2; }

#**********************************
# Command Execution Wrapper
#**********************************
runCmd() { 
  if [ "$dryRun" = true ]; then
    echo "[DRY-RUN] $*"
  else
    logDebug "Running: $*"
    "$@"
  fi
}

#**********************************
# Argument Parsing
#**********************************
parseArgs() {
  for arg in "$@"; do
    case "$arg" in
      --dry-run) dryRun=true ;;
      --verbose) verbose=true ;;
      --help) showHelp; exit 0 ;;
      *) logError "Unknown argument: $arg"; exit 1 ;;
    esac
  done
}

#**********************************
# Environment Detection
#**********************************
detectShellRc() {
  if [ -n "${ZSH_VERSION:-}" ]; then
    echo "$HOME/.zshrc"
  elif [ -n "${BASH_VERSION:-}" ]; then
    echo "$HOME/.bashrc"
  else
    echo "$HOME/.profile"
  fi
}

#**********************************
# Preconditions
#**********************************
checkDependencies() {
  local missing=()
  for cmd in curl grep mkdir; do
    if ! command -v "$cmd" >/dev/null 2>&1; then
      missing+=("$cmd")
    fi
  done
  if [ ${#missing[@]} -ne 0 ]; then
    logError "Missing dependencies: ${missing[*]}"
    exit 1
  fi
}

#**********************************
# Idempotency Helpers
#**********************************
commandExists() { command -v "$1" >/dev/null 2>&1; }

ensureInstalled() {
  local name="$1"
  shift
  if commandExists "$name"; then
    logInfo "$name already installed, skipping"
  else
    "$@"
  fi
}

#**********************************
# Directory Setup
#**********************************
ensureDirectories() {
  logInfo "Ensuring directories exist"
  runCmd mkdir -p "$miseBinDir"
  runCmd mkdir -p "$miseDataDir"
}

#**********************************
# Installers
#**********************************
installMise() {
  logInfo "Installing mise..."
  runCmd bash -c "
    export MISE_BIN_DIR='$miseBinDir'
    export MISE_DATA_DIR='$miseDataDir'
    curl -fsSL $miseInstallUrl | sh
  "
}

installNode() {
  logInfo "Installing Node.js version $NODE_VERSION..."
  runCmd mise use -g node@"$NODE_VERSION"
}

installPython() {
  logInfo "Installing Python version $PYTHON_VERSION..."
  runCmd mise use -g python@"$PYTHON_VERSION"
}

installJava() {
  logInfo "Installing Java version $JAVA_VERSION..."
  runCmd mise use -g java@"$JAVA_VERSION"
}

#**********************************
# Configuration
#**********************************
addActivationToShell() {
  local shellRc
  shellRc=$(detectShellRc)
  logInfo "Configuring shell: $shellRc"
  if ! grep -q 'mise activate' "$shellRc" 2>/dev/null; then
    runCmd bash -c "{
      echo '';
      echo '# mise activation';
      echo 'export PATH=\"$miseBinDir:\$PATH\"';
      echo 'eval \"\$($miseBin activate)\"';
    } >> \"$shellRc\""
  else
    logInfo "Activation already present"
  fi
}

activateMiseNow() {
  export PATH="$miseBinDir:$PATH"
  if [ -x "$miseBin" ]; then
    eval "$("$miseBin" activate)"
  else
    logError "mise not found in $miseBinDir"
    exit 1
  fi
}

#**********************************
# Bootstrap Pipeline
#**********************************
bootstrapCore() {
  ensureDirectories
  ensureInstalled mise installMise
  addActivationToShell
  activateMiseNow
}

bootstrapLanguages() {
  ensureInstalled node installNode
  ensureInstalled python installPython
  ensureInstalled java installJava
}

#**********************************
# Main
#**********************************
main() {
  parseArgs "$@"
  checkDependencies
  bootstrapCore
  bootstrapLanguages
  logSuccess "Bootstrap complete"
}

main "$@"

