#!/usr/bin/env bash
# Copyright 2026 Schelling Point Labs Inc
# --- BUNDLED INSTALL SCRIPT ---
# This is an auto-generated bundled version. For development, see install/ directory.
#
# Usage: curl -fsSL https://install.agent-harbor.com | bash

set -euo pipefail

# ============================================================================
# Build provenance (embedded at bundle time)
# ============================================================================
BUILD_COMMIT_SHA="b7060bf3ba8b116fbcc2c834bebca62dd0510c13"
BUILD_PR_URL=""
BUILD_IS_PR="false"

# ============================================================================
# PART 1: Embedded lib/common.sh
# ============================================================================
# Copyright 2026 Schelling Point Labs Inc
#
# Common utilities for Agent Harbor installation scripts
# This library provides shared functions for platform detection,
# command checking, HTTP fetching, logging, and error handling.
#
# Usage:
#   source "$(dirname "$0")/lib/common.sh"

# Enable strict mode if not already enabled
set -euo pipefail

# ============================================================================
# Configuration
# ============================================================================

# Cachix configuration
CACHIX_URL="${CACHIX_URL:-https://agent-harbor.cachix.org}"
CACHIX_KEY="${CACHIX_KEY:-agent-harbor.cachix.org-1:2x123W9OUoHUzXoSvPv2CRXPo7rjLKAOd6/MkaHFNRA=}"
NIXPKGS_KEY="${NIXPKGS_KEY:-cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=}"

# Allow disabling colors
NO_COLOR="${NO_COLOR:-false}"

# ============================================================================
# Terminal colors
# ============================================================================

setup_colors() {
  if [[ "${NO_COLOR}" == "true" ]] || ! [[ -t 1 ]]; then
    RED=''
    GREEN=''
    YELLOW=''
    BLUE=''
    BOLD=''
    NC=''
  else
    RED='\033[0;31m'
    GREEN='\033[0;32m'
    YELLOW='\033[1;33m'
    BLUE='\033[0;34m'
    BOLD='\033[1m'
    NC='\033[0m'
  fi
}

# Initialize colors
setup_colors

# ============================================================================
# Logging functions
# ============================================================================

# Verbose mode flag - set to "true" to enable debug output
VERBOSE="${VERBOSE:-false}"

info() {
  printf "%b[INFO]%b %s\n" "${GREEN}" "${NC}" "$*" >&2
}

warn() {
  printf "%b[WARN]%b %s\n" "${YELLOW}" "${NC}" "$*" >&2
}

error() {
  printf "%b[ERROR]%b %s\n" "${RED}" "${NC}" "$*" >&2
}

die() {
  error "$*"
  exit 1
}

step() {
  printf "\n%b==>%b %b%s%b\n" "${BLUE}" "${NC}" "${BOLD}" "$*" "${NC}" >&2
}

# Debug logging - only prints when VERBOSE is "true"
debug() {
  if [[ "$VERBOSE" == "true" ]]; then
    printf "%b[DEBUG]%b %s\n" "${BLUE}" "${NC}" "$*" >&2
  fi
}

# ============================================================================
# Confirmation for dangerous commands
# ============================================================================

# Check if running in non-interactive mode (no terminal access)
# Returns 0 if non-interactive, 1 if interactive
is_non_interactive() {
  # If stdin is a TTY, we're definitely interactive
  if [[ -t 0 ]] && [[ -t 1 ]]; then
    return 1
  fi

  # Even with piped stdin (curl | bash), we might have a controlling terminal
  # Check if /dev/tty is available for user interaction
  if [[ -r /dev/tty ]] && [[ -c /dev/tty ]]; then
    # We can read from the controlling terminal
    return 1
  fi

  # No TTY access at all - truly non-interactive
  return 0
}

# Confirm a dangerous action with the user
# Usage: confirm_danger <intent_description> <command_description> [default_answer]
#   intent_description: What we're trying to accomplish (e.g., "Install Nix package manager")
#   command_description: The actual command that will run (e.g., "curl ... | sh -s -- install")
#   default_answer: "y" or "n" (default: "y" if interactive, "n" if non-interactive)
# Returns: 0 if confirmed, 1 if declined
confirm_danger() {
  local intent="$1"
  local command="$2"
  local default_answer="${3:-}"

  # Auto-confirm if explicitly requested
  if [[ "${NO_CONFIRM:-false}" == "true" ]]; then
    return 0
  fi

  # Set default based on interactivity if not provided
  if [[ -z "$default_answer" ]]; then
    if is_non_interactive; then
      default_answer="n"
    else
      default_answer="y"
    fi
  fi

  printf "\n" >&2
  step "$intent"

  # Print the command in a visually distinct block
  printf "%b┃%b %s\n" "${BLUE}" "${NC}" "This will run the following command:" >&2
  printf "%b┃%b\n" "${BLUE}" "${NC}" >&2
  # Indent multi-line commands for readability
  echo "$command" | while IFS= read -r line; do
    printf "%b┃%b   %s\n" "${BLUE}" "${NC}" "$line" >&2
  done
  printf "%b┃%b\n" "${BLUE}" "${NC}" >&2

  # In non-interactive mode, use default answer
  if is_non_interactive; then
    if [[ "$default_answer" == "y" ]]; then
      info "Non-interactive mode: proceeding (default: yes)"
      return 0
    else
      warn "Non-interactive mode: skipping (default: no)"
      return 1
    fi
  fi

  # Interactive prompt
  local prompt_text
  if [[ "$default_answer" == "y" ]]; then
    prompt_text="[Y/n]"
  else
    prompt_text="[y/N]"
  fi

  printf "%b[CONFIRM]%b Do you want to proceed? %s " "${YELLOW}" "${NC}" "$prompt_text" >&2

  local response
  if ! read -r response </dev/tty 2>/dev/null; then
    # Failed to read from terminal (race condition or terminal detached)
    warn "Could not read from terminal, using default: $default_answer"
    if [[ "$default_answer" == "y" ]]; then
      return 0
    else
      return 1
    fi
  fi

  # Normalize response
  response=$(echo "$response" | tr '[:upper:]' '[:lower:]' | tr -d '[:space:]')

  if [[ -z "$response" ]]; then
    response="$default_answer"
  fi

  if [[ "$response" == "y" || "$response" == "yes" ]]; then
    return 0
  fi

  warn "User declined: $intent"
  return 1
}

# ============================================================================
# Command checking
# ============================================================================

# Check if a command exists
need_cmd() {
  if ! command -v "$1" >/dev/null 2>&1; then
    die "Required command not found: $1"
  fi
}

# Check if a command exists, return 0/1
has_cmd() {
  command -v "$1" >/dev/null 2>&1
}

# ============================================================================
# HTTP fetching
# ============================================================================

# Fetch a URL to stdout using curl or wget
# Usage: fetch <url> [extra_curl_args...]
fetch() {
  local url="$1"
  shift

  if has_cmd curl; then
    curl -fsSL "$@" "$url"
  elif has_cmd wget; then
    wget -q "$@" -O - "$url"
  else
    die "Neither curl nor wget is available. Please install one of them."
  fi
}

# Fetch a URL and save to file
# Usage: fetch_to <url> <output_file> [extra_curl_args...]
fetch_to() {
  local url="$1"
  local output="$2"
  shift 2

  if has_cmd curl; then
    curl -fsSL "$@" -o "$output" "$url"
  elif has_cmd wget; then
    wget -q "$@" -O "$output" "$url"
  else
    die "Neither curl nor wget is available. Please install one of them."
  fi
}

# ============================================================================
# Platform detection
# ============================================================================

# Detect platform in nix format: x86_64-linux, aarch64-linux, etc.
detect_platform() {
  local arch os
  arch=$(uname -m)
  os=$(uname -s | tr '[:upper:]' '[:lower:]')

  case "$os" in
  linux)
    case "$arch" in
    x86_64 | amd64) echo "x86_64-linux" ;;
    aarch64 | arm64) echo "aarch64-linux" ;;
    *) die "Unsupported Linux architecture: $arch" ;;
    esac
    ;;
  darwin)
    case "$arch" in
    x86_64 | amd64) echo "x86_64-darwin" ;;
    aarch64 | arm64) echo "aarch64-darwin" ;;
    *) die "Unsupported macOS architecture: $arch" ;;
    esac
    ;;
  *) die "Unsupported operating system: $os" ;;
  esac
}

# Detect OS/distribution ID
detect_os() {
  if [[ -f /etc/os-release ]]; then
    # shellcheck source=/dev/null
    source /etc/os-release
    echo "$ID"
  elif command -v uname >/dev/null 2>&1; then
    uname -s | tr '[:upper:]' '[:lower:]'
  else
    echo "unknown"
  fi
}

# Detect OS version
detect_os_version() {
  if [[ -f /etc/os-release ]]; then
    # shellcheck source=/dev/null
    source /etc/os-release
    echo "$VERSION_ID"
  else
    echo "unknown"
  fi
}

# ============================================================================
# Privilege escalation
# ============================================================================

# Check if running as root
is_root() {
  [[ "$(id -u)" -eq 0 ]]
}

# Return "sudo" if not root, empty string if root
# Usage: $(maybe_sudo) command...
maybe_sudo() {
  if is_root; then
    echo ""
  else
    echo "sudo"
  fi
}

# Check if we have root privileges, set up sudo if needed
ensure_privileges() {
  if is_root; then
    # Already root
    return 0
  fi

  if ! has_cmd sudo; then
    die "This script requires root privileges, but sudo is not available."
  fi

  info "This script requires root privileges. You may be prompted for your password."

  # Validate sudo credentials
  if ! sudo -v >/dev/null 2>&1; then
    die "sudo authentication failed. Please ensure you have sudo access."
  fi
}

# ============================================================================
# Store paths (embedded at build time)
# ============================================================================

# Store paths for each platform, embedded directly in the install script.
# These are populated by `just generate-install-script` at build time.
# When empty, installation will fall back to an error message.
STORE_PATH_x86_64_linux="${STORE_PATH_x86_64_linux:-/nix/store/1g9cncf999qwrdbqrf81z01r99g5x4ww-agent-harbor-cli}"
STORE_PATH_aarch64_darwin="${STORE_PATH_aarch64_darwin:-/nix/store/5xrdz3zhxqybpj9hp6kdm33l0i5vrmhl-agent-harbor-cli-0.1.0}"

# Agent bundle store paths (populated by `just generate-install-script`)
STORE_PATH_AGENTS_x86_64_linux="${STORE_PATH_AGENTS_x86_64_linux:-/nix/store/gd8mypjaz3a0wlgc9y4bnsbzb2ssiaai-ah-agents}"
STORE_PATH_AGENTS_aarch64_darwin="${STORE_PATH_AGENTS_aarch64_darwin:-/nix/store/i0m2smnpjsa50pm0lvpl73pg26ylkan1-ah-agents}"

# Get the embedded store path for the current platform
# Returns the store path on stdout, or returns 1 if not available
get_store_path() {
  local platform
  platform=$(detect_platform)

  local store_path=""
  case "$platform" in
  x86_64-linux) store_path="$STORE_PATH_x86_64_linux" ;;
  aarch64-darwin) store_path="$STORE_PATH_aarch64_darwin" ;;
  *) die "Unsupported platform: $platform" ;;
  esac

  if [[ -z "$store_path" ]]; then
    warn "No store path embedded for platform: $platform"
    warn "The install script may not have been built with store paths."
    warn "Run 'just generate-install-script' to regenerate."
    return 1
  fi

  info "Store path for $platform: $store_path"
  echo "$store_path"
}

# Get the embedded agent bundle store path for the current platform.
# Returns the store path on stdout, or returns 1 if not available.
get_agents_store_path() {
  local platform
  platform=$(detect_platform)

  local store_path=""
  case "$platform" in
  x86_64-linux) store_path="$STORE_PATH_AGENTS_x86_64_linux" ;;
  aarch64-darwin) store_path="$STORE_PATH_AGENTS_aarch64_darwin" ;;
  *) return 1 ;;
  esac

  if [[ -z "$store_path" ]]; then
    return 1
  fi

  debug "Agent bundle store path for $platform: $store_path"
  echo "$store_path"
}

# ============================================================================
# AI coding agent installation
# ============================================================================

# Agent installation mode: "yes", "no", or empty (prompt interactively)
INSTALL_AGENTS="${INSTALL_AGENTS:-}"

# Prompt user to install AI coding agents after the main CLI install.
# Only called for Nix-based installations. Skipped in non-interactive mode
# unless --with-agents is explicitly passed.
prompt_agent_install() {
  if [[ "$INSTALL_AGENTS" == "no" ]]; then
    info "Skipping agent installation (--without-agents)"
    return 0
  fi

  if [[ "$INSTALL_AGENTS" == "yes" ]]; then
    install_agents
    return $?
  fi

  # In non-interactive mode without explicit flag, skip
  if is_non_interactive; then
    info "Non-interactive mode: skipping agent installation"
    info "Use --with-agents to include AI coding agents"
    return 0
  fi

  printf "\n"
  step "AI Coding Agents"
  printf "\n"
  printf "Agent Harbor can install AI coding agents into your PATH.\n"
  printf "The following agents are included in the bundle:\n"
  printf "\n"
  printf "  • Claude Code           (Anthropic)\n"
  printf "  • Gemini CLI            (Google)\n"
  printf "  • OpenCode              (open source)\n"
  printf "  • Codex                 (OpenAI)\n"
  printf "  • Goose                 (Block)\n"
  printf "  • Amp                   (Sourcegraph)\n"
  printf "  • Qwen Code             (Alibaba)\n"
  printf "  • Cursor CLI            (Cursor)\n"
  printf "  • Windsurf              (Codeium)      [Linux x86_64 only]\n"
  printf "  • Copilot CLI, ccusage, crush, and more\n"
  printf "\n"
  printf "Install all AI coding agents? [Y/n]: "

  local response
  if ! read -r response </dev/tty 2>/dev/null; then
    debug "Could not read from terminal, skipping agent installation"
    return 0
  fi

  response=$(echo "$response" | tr '[:upper:]' '[:lower:]' | tr -d '[:space:]')

  case "$response" in
  "" | y | yes)
    install_agents
    ;;
  n | no)
    info "Skipping AI agent installation"
    info "You can install agents later with:"
    info "  nix profile add github:blocksense-network/agent-harbor#ah-agents"
    ;;
  *)
    warn "Invalid choice, skipping agent installation"
    info "You can install agents later with:"
    info "  nix profile add github:blocksense-network/agent-harbor#ah-agents"
    ;;
  esac
}

# Install AI coding agents from the embedded store path.
# Unlike the main CLI, there is no github flake fallback because the repo
# may be private. Agents are only available in bundled install scripts that
# have the store path pre-embedded.
install_agents() {
  info "Installing AI coding agents..."

  local agents_store_path=""
  agents_store_path=$(get_agents_store_path 2>/dev/null) || true

  if [[ -z "$agents_store_path" ]]; then
    warn "Agent bundle not available in this install script"
    info "You can install agents manually after the repo is public:"
    info "  nix profile add github:blocksense-network/agent-harbor#ah-agents"
    return 1
  fi

  if install_from_store_path "$agents_store_path"; then
    info "AI coding agents installed successfully! 🤖"
    return 0
  fi

  warn "Failed to install AI coding agents from binary cache"
  return 1
}

# ============================================================================
# Package manager confirmation helpers
# ============================================================================

# Confirm native package manager installation
# This provides a consistent confirmation experience across all package managers
# Usage: confirm_package_manager_install <pm_name> <pm_description> [commands...]
confirm_package_manager_install() {
  local pm_name="$1"
  local pm_description="$2"
  shift 2

  local intent="Install Agent Harbor via $pm_name
This will use $pm_description to install Agent Harbor and set up
our official repository for future updates."

  # Build command list from remaining arguments
  local commands=""
  for cmd in "$@"; do
    if [[ -n "$commands" ]]; then
      commands="$commands
$cmd"
    else
      commands="$cmd"
    fi
  done

  confirm_danger "$intent" "$commands" "y"
}

# ============================================================================
# Interactive installation method selection
# ============================================================================

# Return 0 when the current bundled installer represents a PR build.
is_pr_build_context() {
  if [[ "${BUILD_IS_PR:-}" == "true" ]] || [[ "${BUILD_IS_PR:-}" == "1" ]]; then
    return 0
  fi

  [[ -n "${BUILD_PR_URL:-}" ]]
}

# Display installation method comparison and prompt user for choice.
# Runs system checks first (OS detection, Nix availability, native package
# manager detection) and presents results alongside the options so the user
# can make an informed decision.
# Sets INSTALL_MODE to "nix" or "native" based on user input.
# Returns 0 on success, 1 if cannot prompt (non-interactive) or user cancels.
prompt_install_method() {
  # If we're in non-interactive mode without explicit choice, we can't prompt
  if is_non_interactive; then
    error "Cannot prompt for installation method in non-interactive mode."
    error "Please specify --nix or --native explicitly."
    error ""
    error "Example: curl -fsSL https://install.agent-harbor.com/install.sh | bash -s -- --nix"
    return 1
  fi

  # ------------------------------------------------------------------
  # Run system checks upfront
  # ------------------------------------------------------------------
  local distro
  distro=$(detect_os)

  local nix_installed="no"
  ensure_nix_profile_in_path
  if check_nix_installed 2>/dev/null; then
    nix_installed="yes"
  fi

  local native_available="no"
  local pkg_manager="unknown"
  case "$distro" in
  debian | ubuntu | fedora | rhel | centos | rocky | almalinux | amzn | alpine | arch | manjaro | opensuse | darwin)
    native_available="yes"
    # detect_package_manager is defined in install-native.sh; guard in case
    # we're running inside the bundled script where it may not exist yet.
    if type -t detect_package_manager &>/dev/null; then
      pkg_manager=$(detect_package_manager "$distro")
    else
      # Inline fallback matching install-native.sh logic
      case "$distro" in
      debian | ubuntu) pkg_manager="apt" ;;
      fedora) pkg_manager="dnf" ;;
      rhel | centos | rocky | almalinux | amzn) pkg_manager="yum" ;;
      alpine) pkg_manager="apk" ;;
      arch | manjaro) pkg_manager="pacman" ;;
      opensuse) pkg_manager="zypper" ;;
      darwin) pkg_manager="macos" ;;
      esac
    fi
    ;;
  esac

  # ------------------------------------------------------------------
  # Display detected system information
  # ------------------------------------------------------------------
  printf "\n"
  step "Choose Installation Method"
  printf "\n"

  printf "%bSystem check results:%b\n" "${BOLD}" "${NC}"
  printf "  OS/distro detected: %b%s%b\n" "${BOLD}" "$distro" "${NC}"

  if [[ "$nix_installed" == "yes" ]]; then
    printf "  Nix package manager: %b✓ installed%b\n" "${GREEN}" "${NC}"
  else
    printf "  Nix package manager: %b✗ not installed%b (can be set up automatically)\n" "${YELLOW}" "${NC}"
  fi

  if [[ "$native_available" == "yes" ]]; then
    printf "  Native package manager: %b✓ %s%b\n" "${GREEN}" "$pkg_manager" "${NC}"
  else
    printf "  Native package manager: %b✗ unsupported distro%b\n" "${RED}" "${NC}"
  fi
  printf "\n"

  # ------------------------------------------------------------------
  # Check if this is a PR build where native packages are intentionally disabled.
  # Main/release installers still embed BUILD_COMMIT_SHA for provenance, so commit SHA
  # alone is not a reliable signal for gating native installation.
  # ------------------------------------------------------------------
  local is_pr_build="no"
  if is_pr_build_context; then
    is_pr_build="yes"
  fi

  # ------------------------------------------------------------------
  # Show option details
  # ------------------------------------------------------------------

  PRO="${GREEN}+${NC}"
  CON="${RED}-${NC}"

  printf "%b1) Nix Installation%b" "${BOLD}" "${NC}"
  if [[ "$nix_installed" == "yes" ]]; then
    printf "  %b★ Nix already installed — fast path!%b" "${GREEN}" "${NC}"
  fi
  printf "\n"
  printf "   ${PRO} %b\n" \
    "Fast binary cache install (seconds, not minutes)" \
    "Option to install AI coding agents (Claude Code, Goose, Gemini, OpenCode, Codex, Amp, etc.)" \
    "Node.js, npm, and all needed runtimes included" \
    "Can install/update/delete packages atomically and securely" \
    "Isolated in \`/nix\` — doesn't interfere with system"
  printf "   ${CON} %b\n" \
    "One-time Nix setup required (<1GB storage)" \
    "Newer ecosystem, may be unfamiliar"
  printf "\n"

  printf "%b2) Native Installation%b" "${BOLD}" "${NC}"
  if [[ "$is_pr_build" == "yes" ]]; then
    printf "  %b⚠ native packages are not available from arbitrary commits%b" "${RED}" "${NC}"
  elif [[ "$native_available" == "yes" ]]; then
    printf "  %b(via %s)%b" "${GREEN}" "$pkg_manager" "${NC}"
  else
    printf "  %b⚠ not available for %s%b" "${RED}" "$distro" "${NC}"
  fi
  printf "\n"
  printf "   ${PRO} %b\n" \
    "Uses system package manager (${pkg_manager})" \
    "No extra package manager needed" \
    "Familiar workflow for sysadmins" \
    "Integrates with system updates"
  printf "   ${CON} %b\n" \
    "AI agents NOT in distro repos — must install separately" \
    "Platform-specific, \`root\`/\`sudo\` often required"
  printf "\n"

  # ------------------------------------------------------------------
  # Determine default choice
  # ------------------------------------------------------------------
  local default_choice="1"

  if [[ "$is_pr_build" == "yes" ]]; then
    # Per-commit builds only have Nix packages available
    default_choice="1"
  elif [[ "$nix_installed" == "yes" ]]; then
    # Nix is already there — it's the obvious fast path
    default_choice="1"
  elif [[ "$native_available" == "no" ]]; then
    # Can't do native anyway
    default_choice="1"
  else
    # Both available, no Nix yet — default to native (no extra tooling)
    default_choice="2"
  fi

  local prompt_text="[1/2, default: ${default_choice}]"

  printf "Enter your choice %s: " "$prompt_text"

  local response
  if ! read -r response </dev/tty 2>/dev/null; then
    warn "Could not read from terminal, using default: $default_choice"
    response="$default_choice"
  fi

  # Normalize and validate response
  response=$(echo "$response" | tr -d '[:space:]')
  if [[ -z "$response" ]]; then
    response="$default_choice"
  fi

  case "$response" in
  1 | nix | Nix | NIX)
    INSTALL_MODE="nix"
    info "Selected: Nix installation"
    ;;
  2 | native | Native | NATIVE)
    if [[ "$is_pr_build" == "yes" ]]; then
      warn "Native installation is not available for per-commit builds"
      info "Native packages are only published for tagged releases"
      info "Falling back to Nix installation"
      INSTALL_MODE="nix"
    elif [[ "$native_available" != "yes" ]]; then
      warn "Native installation is not available for $distro"
      info "Falling back to Nix installation"
      INSTALL_MODE="nix"
    else
      INSTALL_MODE="native"
      info "Selected: Native installation"
    fi
    ;;
  *)
    warn "Invalid choice: $response"
    info "Please enter '1' for Nix or '2' for Native"
    return 1
    ;;
  esac

  printf "\n"
  return 0
}

# ============================================================================
# Nix installation helpers
# ============================================================================

# Check if Nix is already installed
check_nix_installed() {
  debug "Checking for 'nix' command..."
  has_cmd nix
}

# Ensure Nix profile directories are in PATH
# This is needed when running via "curl | bash" where the current shell
# doesn't inherit the user's normal shell environment with .nix-profile/bin
ensure_nix_profile_in_path() {
  # User profile (nix profile add installs here)
  if [[ -d "$HOME/.nix-profile/bin" ]] && [[ ":$PATH:" != *":$HOME/.nix-profile/bin:"* ]]; then
    export PATH="$HOME/.nix-profile/bin:$PATH"
  fi
  # System profile (daemon installs here)
  if [[ -d "/nix/var/nix/profiles/default/bin" ]] && [[ ":$PATH:" != *":/nix/var/nix/profiles/default/bin:"* ]]; then
    export PATH="/nix/var/nix/profiles/default/bin:$PATH"
  fi
}

# Check if Agent Harbor CLI is already installed
# Returns 0 if installed, 1 otherwise
is_ah_installed() {
  ensure_nix_profile_in_path
  command -v ah >/dev/null 2>&1
}

# Handle already-installed scenario
# Prints appropriate message and returns 0 (caller decides what to do)
handle_already_installed() {
  info "Agent Harbor CLI is already installed"
  ah --version
  info "Run 'ah --help' to get started, or reinstall to update"
  return 0
}

# Verify installation and print appropriate message
# Returns 0 if ah is found, 1 otherwise (but doesn't exit)
verify_installation() {
  # Ensure PATH is up to date before checking
  ensure_nix_profile_in_path

  # Detect if we can persist PATH changes:
  # - Sourced script: yes (runs in parent shell)
  # - Terminal stdin: no (script cannot modify parent environment)
  # - Pipe stdin: no (curl|bash, script cannot modify parent environment)
  local can_persist_path=false
  if [[ -t 0 ]] && [[ "${BASH_SOURCE[0]}" != "${0}" ]]; then
    # Interactive terminal AND sourced (source script.sh)
    can_persist_path=true
  fi

  if is_ah_installed; then
    info ""
    info "✅ Agent Harbor CLI installed!"
    ah --version

    # If PATH changes won't persist, advise user
    if [[ "$can_persist_path" != true ]]; then
      info ""
      info "Note: Run 'exec \$SHELL' to use 'ah' in this terminal"
      info "      (Scripts cannot modify parent shell environment)"
    fi
    return 0
  else
    warn "'ah' not immediately available in current shell"
    info ""
    info "Installation complete! 🎉"
    info "To use 'ah', start a new shell session or run: exec \$SHELL"
    return 1
  fi
}

# Unified entry point handler - checks if installed, returns 1 to signal "proceed with install"
# Usage: check_existing_installation || return 0
check_existing_installation() {
  ensure_nix_profile_in_path
  if is_ah_installed; then
    handle_already_installed
    return 1 # Signal to caller: don't proceed with installation
  fi
  return 0 # Proceed with installation
}

# Install Nix package manager
# Returns 0 on success, 1 on failure.
install_nix() {
  if check_nix_installed; then
    info "Nix already installed: $(nix --version)"
    return 0
  fi

  local os
  os=$(uname -s | tr '[:upper:]' '[:lower:]')

  # Build the command description based on platform
  local nix_installer_cmd
  local intent="Install Nix package manager"

  case "$os" in
  linux)
    nix_installer_cmd="curl -fsSL https://artifacts.nixos.org/nix-installer | sh -s -- install linux --no-confirm --init none"
    ;;
  darwin)
    nix_installer_cmd="curl -fsSL https://artifacts.nixos.org/nix-installer | sh -s -- install macos --no-confirm"
    ;;
  *)
    error "Unsupported platform for Nix installation: $os"
    return 1
    ;;
  esac

  # Add context about what Nix is
  local full_intent
  full_intent="$intent
This will install the Nix package manager from the official NixOS installer.
Nix is a powerful package manager that enables reproducible builds and
will allow Agent Harbor to be installed from our binary cache.
After installation, Nix will:
- Create /nix directory for storing packages
- Configure the Nix daemon and nixbld users for multi-user builds
- Add Cachix binary cache for faster Agent Harbor installs"

  # Confirm before installing Nix
  if ! confirm_danger "$full_intent" "$nix_installer_cmd" "y"; then
    warn "Nix installation declined by user"
    info "You can install Nix manually: https://nixos.org/download"
    return 1
  fi

  info "Installing Nix package manager..."

  case "$os" in
  linux)
    if ! fetch "https://artifacts.nixos.org/nix-installer" | sh -s -- install linux --no-confirm --init none; then
      error "Nix installer failed on Linux"
      return 1
    fi
    ;;
  darwin)
    if ! fetch "https://artifacts.nixos.org/nix-installer" | sh -s -- install macos --no-confirm; then
      error "Nix installer failed on macOS"
      return 1
    fi
    ;;
  esac

  # Source the Nix environment (Linux only)
  if [[ "$os" == "linux" ]]; then
    # shellcheck source=/dev/null
    if [[ -f /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh ]]; then
      . /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh
    fi
  fi

  # Configure Nix
  mkdir -p ~/.config/nix

  if [[ -n "${GITHUB_TOKEN:-}" ]]; then
    echo "access-tokens = github.com=$GITHUB_TOKEN" >>~/.config/nix/nix.conf
  fi

  cat >>~/.config/nix/nix.conf <<EOF
experimental-features = nix-command flakes
extra-substituters = $CACHIX_URL
extra-trusted-public-keys = $NIXPKGS_KEY $CACHIX_KEY
narinfo-cache-negative-ttl = 0
EOF

  info "Nix installed and configured"
}

# Install a package using nix profile (handles different nix versions)
nix_profile_install() {
  local target="$1"
  local extra_args=("${@:2}")

  # Try nix profile add first (preferred, non-deprecated)
  if nix profile add --help >/dev/null 2>&1; then
    debug "Using 'nix profile add'"
    nix profile add "$target" "${extra_args[@]}"
    return $?
  fi

  # Fall back to nix profile install (deprecated alias)
  if nix profile install --help >/dev/null 2>&1; then
    debug "Using 'nix profile install' (deprecated)"
    nix profile install "$target" "${extra_args[@]}"
    return $?
  fi

  # Fall back to nix-env (legacy)
  debug "Using 'nix-env -i' (legacy)"
  nix-env -i "$target"
}

# Track whether we've already offered the Nix trust self-heal during this run.
NIX_TRUST_PREFLIGHT_DONE="${NIX_TRUST_PREFLIGHT_DONE:-false}"

# Run a command with sudo when needed.
run_maybe_sudo() {
  if is_root; then
    "$@"
  else
    sudo "$@"
  fi
}

# Return 0 if current user appears in effective Nix trusted-users.
nix_current_user_is_trusted() {
  local current_user trusted_users token group_name
  current_user="$(id -un 2>/dev/null || true)"
  if [[ -z "$current_user" ]]; then
    return 1
  fi

  trusted_users="$(nix show-config trusted-users 2>/dev/null | sed -n 's/^trusted-users = //p' || true)"
  if [[ -z "$trusted_users" ]]; then
    return 1
  fi

  for token in $trusted_users; do
    case "$token" in
    "*")
      return 0
      ;;
    "$current_user")
      return 0
      ;;
    @*)
      group_name="${token#@}"
      if id -nG "$current_user" 2>/dev/null | tr ' ' '\n' | grep -Fxq "$group_name"; then
        return 0
      fi
      ;;
    esac
  done

  return 1
}

# Choose the system-level Nix config file to update.
nix_system_config_file() {
  if [[ -f /etc/nix/nix.custom.conf ]]; then
    echo "/etc/nix/nix.custom.conf"
    return 0
  fi

  echo "/etc/nix/nix.conf"
}

# Return 0 if a Nix config file already trusts the specified user.
nix_config_trusts_user() {
  local config_file="$1"
  local user_name="$2"

  # shellcheck disable=SC2016
  run_maybe_sudo awk -F '=' -v user_name="$user_name" '
    /^[[:space:]]*(trusted-users|extra-trusted-users)[[:space:]]*=/ {
      value = $2
      gsub(/^[[:space:]]+|[[:space:]]+$/, "", value)
      n = split(value, parts, /[[:space:]]+/)
      for (i = 1; i <= n; i++) {
        if (parts[i] == user_name) {
          found = 1
          exit
        }
      }
    }
    END { exit(found ? 0 : 1) }
  ' "$config_file"
}

# Restart the Nix daemon after system-level config changes.
restart_nix_daemon() {
  local os
  os="$(uname -s | tr '[:upper:]' '[:lower:]')"

  case "$os" in
  darwin)
    run_maybe_sudo launchctl kickstart -k system/org.nixos.nix-daemon
    ;;
  linux)
    if has_cmd systemctl; then
      run_maybe_sudo systemctl restart nix-daemon || run_maybe_sudo systemctl restart nix-daemon.service
    elif has_cmd service; then
      run_maybe_sudo service nix-daemon restart
    else
      warn "Could not find a service manager to restart nix-daemon"
      return 1
    fi
    ;;
  *)
    warn "Unsupported platform for automatic nix-daemon restart: $os"
    return 1
    ;;
  esac
}

# Try to self-heal Nix trusted-user config and daemon restart.
configure_nix_trusted_user() {
  local current_user config_file attempt max_attempts
  current_user="$(id -un 2>/dev/null || true)"
  if [[ -z "$current_user" ]]; then
    warn "Could not determine current user for Nix trust configuration"
    return 1
  fi

  if ! ensure_privileges; then
    return 1
  fi

  config_file="$(nix_system_config_file)"
  info "Using Nix system config: $config_file"

  if ! run_maybe_sudo mkdir -p /etc/nix; then
    warn "Failed to create /etc/nix"
    return 1
  fi

  if ! run_maybe_sudo touch "$config_file"; then
    warn "Failed to create Nix config file: $config_file"
    return 1
  fi

  if nix_config_trusts_user "$config_file" "$current_user"; then
    info "Nix config already trusts '$current_user'"
  else
    if ! printf '\nextra-trusted-users = %s\n' "$current_user" | run_maybe_sudo tee -a "$config_file" >/dev/null; then
      warn "Failed to update Nix trusted users in $config_file"
      return 1
    fi
    info "Added '$current_user' to extra-trusted-users in $config_file"
  fi

  info "Restarting nix-daemon..."
  if ! restart_nix_daemon; then
    warn "Failed to restart nix-daemon automatically"
    return 1
  fi

  # launchd/systemd reload can be asynchronous on some hosts.
  # Poll briefly instead of using a single fixed sleep.
  max_attempts=10
  attempt=1
  while [[ $attempt -le $max_attempts ]]; do
    if nix_current_user_is_trusted; then
      info "Nix daemon now trusts '$current_user'"
      return 0
    fi
    sleep 1
    attempt=$((attempt + 1))
  done

  warn "Nix daemon trust check still failing after automatic configuration"
  return 1
}

# Offer an interactive self-heal when Nix daemon trust is missing.
maybe_offer_nix_trust_self_heal() {
  local current_user os restart_cmd prompt_cmd prompt_intent config_file

  if [[ "${NIX_TRUST_PREFLIGHT_DONE}" == "true" ]]; then
    return 0
  fi

  if ! check_nix_installed; then
    return 0
  fi
  if is_root; then
    return 0
  fi
  if nix_current_user_is_trusted; then
    return 0
  fi
  NIX_TRUST_PREFLIGHT_DONE="true"

  current_user="$(id -un 2>/dev/null || echo "<your-user>")"
  config_file="$(nix_system_config_file)"
  warn "Nix daemon does not trust user '$current_user'."
  warn "This can block Cachix and fail installation."

  if [[ "${NO_CONFIRM:-false}" == "true" ]]; then
    warn "Skipping automatic trust fix in --yes/--no-confirm mode."
    print_nix_untrusted_user_fix
    return 0
  fi

  # Only attempt interactive self-heal when we can reliably access /dev/tty.
  if ! [[ -t 1 ]] || ! (: </dev/tty) 2>/dev/null; then
    warn "Skipping automatic trust fix: no interactive terminal available."
    print_nix_untrusted_user_fix
    return 0
  fi

  os="$(uname -s | tr '[:upper:]' '[:lower:]')"
  case "$os" in
  darwin)
    restart_cmd="sudo launchctl kickstart -k system/org.nixos.nix-daemon"
    ;;
  linux)
    restart_cmd="sudo systemctl restart nix-daemon"
    ;;
  *)
    restart_cmd="# restart nix-daemon for your platform"
    ;;
  esac

  prompt_cmd="sudo sh -c 'echo \"extra-trusted-users = $current_user\" >> $config_file'
$restart_cmd"
  prompt_intent="Enable Nix trusted-user access for this installer run
This updates Nix daemon config to trust '$current_user' and restarts nix-daemon.
Without this, binary-cache installation can fail on this machine."

  if ! confirm_danger "$prompt_intent" "$prompt_cmd" "y"; then
    warn "Skipped automatic Nix trust configuration by user choice."
    return 0
  fi

  if ! configure_nix_trusted_user; then
    print_nix_untrusted_user_fix_warning
  fi

  return 0
}

# Install tmux for Nix installs when it's missing.
# Returns 0 on success, 1 on failure.
ensure_tmux_installed() {
  local tmux_store_path nix_err_file nix_output

  if has_cmd tmux; then
    info "tmux already installed"
    return 0
  fi

  info "Installing tmux terminal multiplexer..."
  nix_err_file="$(mktemp)"
  if ! tmux_store_path="$(
    nix build \
      --print-out-paths \
      --no-link \
      "nixpkgs#tmux" \
      --option extra-substituters "$CACHIX_URL" \
      --option trusted-public-keys "$NIXPKGS_KEY $CACHIX_KEY" \
      --option narinfo-cache-negative-ttl 0 \
      --extra-experimental-features "nix-command flakes" \
      2> >(tee "$nix_err_file" >&2)
  )"; then
    nix_output="$(cat "$nix_err_file")"
    rm -f "$nix_err_file"
    if nix_output_indicates_untrusted_user "$nix_output"; then
      print_nix_untrusted_user_fix
    fi
    warn "Failed to resolve tmux from nixpkgs"
    return 1
  fi
  rm -f "$nix_err_file"

  tmux_store_path="$(printf '%s\n' "$tmux_store_path" | tail -n1)"
  if [[ -z "$tmux_store_path" ]]; then
    warn "Could not determine tmux store path from nix build output"
    return 1
  fi

  if ! install_from_store_path "$tmux_store_path"; then
    warn "Failed to install tmux from store path"
    return 1
  fi

  if ! has_cmd tmux; then
    ensure_nix_profile_in_path
  fi
  if has_cmd tmux; then
    info "tmux installed successfully"
    return 0
  fi

  warn "tmux installation finished but command is not in PATH yet"
  return 1
}

# Detect Nix permission errors caused by untrusted users.
nix_output_indicates_untrusted_user() {
  local output="$1"

  case "$output" in
  *"restricted setting and you are not a trusted user"* | *"ignoring untrusted substituter"* | *"you are not a trusted user"*)
    return 0
    ;;
  *)
    return 1
    ;;
  esac
}

# Print remediation steps for non-trusted-user Nix daemon setups.
print_nix_untrusted_user_fix_inner() {
  local log_fn="${1:-error}"
  local current_user config_file
  current_user="$(id -un 2>/dev/null || echo "<your-user>")"
  config_file="$(nix_system_config_file)"

  "$log_fn" "Nix rejected Cachix cache settings because '$current_user' is not a trusted user."
  "$log_fn" "Fix this once, then rerun the installer:"
  "$log_fn" "  sudo sh -c 'echo \"extra-trusted-users = $current_user\" >> $config_file'"
  case "$(uname -s | tr '[:upper:]' '[:lower:]')" in
  darwin)
    "$log_fn" "  sudo launchctl kickstart -k system/org.nixos.nix-daemon"
    ;;
  linux)
    "$log_fn" "  sudo systemctl restart nix-daemon"
    ;;
  *)
    "$log_fn" "  Restart the Nix daemon for your platform"
    ;;
  esac
  "$log_fn" "If needed, adjust your Nix daemon config file manually before rerunning."
}

# Print hard remediation errors after an actual Nix command fails due to trust.
print_nix_untrusted_user_fix() {
  print_nix_untrusted_user_fix_inner error
}

# Print softer remediation guidance when preflight self-heal cannot be verified yet.
print_nix_untrusted_user_fix_warning() {
  warn "Nix trust self-heal could not be verified immediately after restarting nix-daemon."
  warn "Continuing installation. If a later Nix command reports an untrusted user, run:"
  print_nix_untrusted_user_fix_inner warn
}

# Install from a store path using nix-store -r + nix profile add
# Returns 0 on success, 1 on failure.
install_from_store_path() {
  local store_path="$1"
  local nix_err_file=""
  local nix_output=""

  info "Installing from store path: $store_path"
  debug "Cachix URL: $CACHIX_URL"

  # Fetch from binary cache
  debug "Fetching from binary cache with nix-store -r..."
  nix_err_file="$(mktemp)"
  if ! nix-store -r "$store_path" \
    --option extra-substituters "$CACHIX_URL" \
    --option trusted-public-keys "$NIXPKGS_KEY $CACHIX_KEY" \
    --option narinfo-cache-negative-ttl 0 2> >(tee "$nix_err_file" >&2); then
    nix_output="$(cat "$nix_err_file")"
    rm -f "$nix_err_file"
    if nix_output_indicates_untrusted_user "$nix_output"; then
      print_nix_untrusted_user_fix
    fi
    warn "Failed to fetch from binary cache"
    return 1
  fi
  rm -f "$nix_err_file"

  # Add to user profile
  nix_err_file="$(mktemp)"
  if ! nix_profile_install "$store_path" \
    --option extra-substituters "$CACHIX_URL" \
    --option trusted-public-keys "$NIXPKGS_KEY $CACHIX_KEY" 2> >(tee "$nix_err_file" >&2); then
    nix_output="$(cat "$nix_err_file")"
    rm -f "$nix_err_file"
    if nix_output_indicates_untrusted_user "$nix_output"; then
      print_nix_untrusted_user_fix
    fi
    warn "Profile install failed, binary available at: $store_path/bin"
    return 1
  fi
  rm -f "$nix_err_file"
}

# Install/refresh the systemd unit for ah-fs-snapshots-daemon when using
# non-package Linux installs (Nix profile/store-path). Native packages already
# ship this unit via package metadata.
setup_snapshot_daemon_systemd_unit_for_nix_profile() {
  local store_path="${1:-}"
  local os
  os="$(uname -s | tr '[:upper:]' '[:lower:]')"

  if [[ "$os" != "linux" ]]; then
    return 0
  fi

  local daemon_bin=""
  if [[ -n "$store_path" ]] && [[ -x "$store_path/bin/ah-fs-snapshots-daemon" ]]; then
    daemon_bin="$store_path/bin/ah-fs-snapshots-daemon"
  elif has_cmd ah-fs-snapshots-daemon; then
    daemon_bin="$(command -v ah-fs-snapshots-daemon)"
  else
    warn "Skipping snapshot daemon systemd setup: ah-fs-snapshots-daemon not found"
    return 0
  fi

  local unit_path="/etc/systemd/system/ah-fs-snapshots-daemon.service"
  local tmp_unit
  if ! tmp_unit="$(mktemp)"; then
    warn "Skipping snapshot daemon systemd setup: failed to create temporary file"
    return 0
  fi

  cat >"$tmp_unit" <<EOF
[Unit]
Description=Agent Harbor Filesystem Snapshots Daemon
Documentation=https://github.com/agent-harbor/agent-harbor
Documentation=man:ah-fs-snapshots-daemon(1)
After=network.target local-fs.target
Wants=zfs.target

[Service]
Type=simple
ExecStart=$daemon_bin
Restart=on-failure
RestartSec=5
TimeoutStopSec=30
NoNewPrivileges=no
ProtectSystem=strict
ProtectHome=read-only
PrivateTmp=yes
ReadWritePaths=/mnt /var/lib/agent-harbor /run/agent-harbor
RestrictAddressFamilies=AF_UNIX AF_LOCAL
StandardOutput=journal
StandardError=journal
SyslogIdentifier=ah-fs-snapshots-daemon

[Install]
WantedBy=multi-user.target
EOF

  if is_root; then
    if ! mkdir -p /etc/systemd/system; then
      warn "Failed to create /etc/systemd/system for snapshot daemon unit"
      rm -f "$tmp_unit"
      return 0
    fi
    if ! cp "$tmp_unit" "$unit_path"; then
      warn "Failed to install snapshot daemon unit at $unit_path"
      rm -f "$tmp_unit"
      return 0
    fi
    if ! chmod 0644 "$unit_path"; then
      warn "Failed to set permissions on $unit_path"
      rm -f "$tmp_unit"
      return 0
    fi
  else
    if ! has_cmd sudo; then
      warn "Skipping snapshot daemon systemd setup: sudo is required"
      rm -f "$tmp_unit"
      return 0
    fi
    if ! sudo -v >/dev/null 2>&1; then
      warn "Skipping snapshot daemon systemd setup: sudo authentication failed"
      rm -f "$tmp_unit"
      return 0
    fi
    if ! sudo mkdir -p /etc/systemd/system; then
      warn "Failed to create /etc/systemd/system for snapshot daemon unit"
      rm -f "$tmp_unit"
      return 0
    fi
    if ! sudo cp "$tmp_unit" "$unit_path"; then
      warn "Failed to install snapshot daemon unit at $unit_path"
      rm -f "$tmp_unit"
      return 0
    fi
    if ! sudo chmod 0644 "$unit_path"; then
      warn "Failed to set permissions on $unit_path"
      rm -f "$tmp_unit"
      return 0
    fi
  fi
  rm -f "$tmp_unit"

  info "Installed snapshot daemon systemd unit: $unit_path"
  info "Configured ExecStart=$daemon_bin"

  if has_cmd systemctl; then
    if is_root; then
      if ! systemctl daemon-reload; then
        warn "Failed to reload systemd daemon (unit file was still installed)"
      fi
      info "Enable and start it with: systemctl enable --now ah-fs-snapshots-daemon"
    else
      if ! sudo systemctl daemon-reload; then
        warn "Failed to reload systemd daemon (unit file was still installed)"
      fi
      info "Enable and start it with: sudo systemctl enable --now ah-fs-snapshots-daemon"
    fi
  else
    warn "systemctl not found; installed unit but could not run daemon-reload"
  fi

  return 0
}

# Install ah-fs-snapshots-daemon as a LaunchDaemon on macOS.
# Uses the daemon's built-in `install` subcommand which handles plist creation,
# launchctl bootstrap, and socket verification.
# This function follows the same pattern as setup_snapshot_daemon_systemd_unit_for_nix_profile
# for Linux, leveraging existing sudo access from the install script.
setup_snapshot_daemon_launchd_for_macos() {
  local store_path="${1:-}"
  local os
  os="$(uname -s | tr '[:upper:]' '[:lower:]')"

  if [[ "$os" != "darwin" ]]; then
    return 0
  fi

  local daemon_bin=""
  if [[ -n "$store_path" ]] && [[ -x "$store_path/bin/ah-fs-snapshots-daemon" ]]; then
    daemon_bin="$store_path/bin/ah-fs-snapshots-daemon"
  elif has_cmd ah-fs-snapshots-daemon; then
    daemon_bin="$(command -v ah-fs-snapshots-daemon)"
  else
    warn "Skipping snapshot daemon LaunchDaemon setup: ah-fs-snapshots-daemon not found"
    return 0
  fi

  info "Installing Agent Harbor daemon as LaunchDaemon..."

  # Use the daemon's built-in install subcommand
  # This handles plist creation, launchctl bootstrap, socket verification
  if is_root; then
    if "$daemon_bin" install; then
      info "✓ Daemon installed successfully"
      return 0
    else
      warn "Failed to install daemon. You can install manually later with:"
      warn "  sudo ah-fs-snapshots-daemon install"
      return 0
    fi
  else
    if ! has_cmd sudo; then
      warn "Skipping snapshot daemon LaunchDaemon setup: sudo is required"
      return 0
    fi
    if ! sudo -v >/dev/null 2>&1; then
      warn "Skipping snapshot daemon LaunchDaemon setup: sudo authentication failed"
      return 0
    fi
    if sudo "$daemon_bin" install; then
      info "✓ Daemon installed successfully"
      return 0
    else
      warn "Failed to install daemon. You can install manually later with:"
      warn "  sudo ah-fs-snapshots-daemon install"
      return 0
    fi
  fi
}

# Note: Git-based flake installation has been removed.
# The installer only supports binary cache installation via nix-store.
# This ensures fast, reproducible installs without requiring source builds.
# To install from source, clone the repository and build manually:
#   git clone https://github.com/blocksense-network/agent-harbor
#   cd agent-harbor && nix build .#ah

# ============================================================================
# PART 2: Embedded install-nix.sh (backend functions)
# ============================================================================

# Nix installation backend - installs using Nix + Cachix binary cache
# Embed all functions, rename entry point to run_nix_backend
# Copyright 2026 Schelling Point Labs Inc
#
# Agent Harbor Nix-based installation script
# Installs Agent Harbor CLI using Nix + Cachix binary cache
#
# Usage:
#   ./install-nix.sh [version]
#   VERSION=v1.2.3 ./install-nix.sh


# Get the directory where this script is located

# Source common utilities

# ============================================================================
# Configuration
# ============================================================================

# ============================================================================
# Internal installation function (can be called directly or used standalone)
# ============================================================================

# Run the Nix installation process. Can be called directly when sourced,
# or via main() when run standalone.
# Returns 0 on success, 1 on failure.
run_nix_backend() {
  local platform
  platform=$(detect_platform)
  info "Platform: $platform"
  # Ensure Nix is in PATH first (in case it was installed previously but PATH not set)
  ensure_nix_profile_in_path

  # Check/install Nix
  if ! check_nix_installed; then
    if ! install_nix; then
      error "Failed to install Nix package manager"
      return 1
    fi
    # Ensure PATH is updated immediately after installation
    ensure_nix_profile_in_path
  fi

  # Offer to self-heal daemon trust before store-path install.
  maybe_offer_nix_trust_self_heal

  # Get embedded store path for current platform
  local store_path=""
  if ! store_path=$(get_store_path); then
    error "No store path available for this platform"
    error ""
    error "The installer requires pre-built binaries from the Cachix binary cache."
    error "To build from source instead, clone the repository:"
    error "  git clone https://github.com/blocksense-network/agent-harbor"
    error "  cd agent-harbor && nix build .#ah"
    return 1
  fi

  # Install from store path
  if [[ -n "$store_path" ]]; then
    if ! install_from_store_path "$store_path"; then
      error "Store path installation failed"
      return 1
    fi
    setup_snapshot_daemon_systemd_unit_for_nix_profile "$store_path"
    setup_snapshot_daemon_launchd_for_macos "$store_path"
    # tmux is required for dashboard/session management.
    if ! ensure_tmux_installed; then
      error "tmux installation failed"
      return 1
    fi
  else
    error "No store path available for installation"
    return 1
  fi

  # Return success - verification is handled by caller (dispatcher or main)
  return 0
}



# ============================================================================
# PART 3: Embedded install-native.sh (backend functions)
# ============================================================================

# Native package manager backend - installs using APT/YUM/DNF/APK/etc
# Embed all functions, rename entry point to run_native_backend
# Copyright 2026 Schelling Point Labs Inc
#
# Agent Harbor native package installation script
# Installs Agent Harbor using system package managers (APT, YUM, DNF, APK, etc.)
#
# Usage:
#   ./install-native.sh [options]
#   PACKAGE_VARIANT=agent-harbor-cli ./install-native.sh


# Get the directory where this script is located

# Source common utilities

# ============================================================================
# Configuration
# ============================================================================

# Repository URLs (can be overridden via environment)
APT_REPO_URL="${APT_REPO_URL:-https://apt.agent-harbor.com}"
YUM_REPO_URL="${YUM_REPO_URL:-https://yum.agent-harbor.com}"
ARCH_REPO_URL="${ARCH_REPO_URL:-https://arch.agent-harbor.com}"
APK_REPO_URL="${APK_REPO_URL:-https://apk.agent-harbor.com}"
MACOS_DMG_BASE_URL="${MACOS_DMG_BASE_URL:-https://downloads.agent-harbor.com/macos}"

# Package variant (agent-harbor, agent-harbor-cli, agent-harbor-fs)
PACKAGE_VARIANT="${PACKAGE_VARIANT:-agent-harbor}"
VERSION="${VERSION:-latest}"

# Testing options
SKIP_GPG_CHECK="${SKIP_GPG_CHECK:-false}"

# ============================================================================
# Package manager detection and installation
# ============================================================================

# Detect the package manager based on OS/distro
detect_package_manager() {
  local distro="$1"

  case "$distro" in
  debian | ubuntu) echo "apt" ;;
  fedora) echo "dnf" ;;
  rhel | centos | rocky | almalinux | amzn) echo "yum" ;;
  alpine) echo "apk" ;;
  arch | manjaro) echo "pacman" ;;
  opensuse) echo "zypper" ;;
  darwin) echo "macos" ;;
  *) echo "unknown" ;;
  esac
}

# Install using APT (Debian, Ubuntu)
install_apt() {
  step "Installing via APT"

  local SUDO
  SUDO=$(maybe_sudo)

  # Check if gpg is available when needed
  if [[ "$SKIP_GPG_CHECK" != "true" ]] && ! has_cmd gpg; then
    warn "gpg command not found - required for GPG key verification"
    warn "Install gpg with: apt-get install gnupg"
    warn "Or set SKIP_GPG_CHECK=true to skip GPG verification (not recommended)"
    return 1
  fi

  # Build command preview for confirmation
  local commands=""
  if [[ "$SKIP_GPG_CHECK" != "true" ]]; then
    commands="mkdir -p /etc/apt/keyrings
fetch ${APT_REPO_URL}/gpg-key.asc | gpg --dearmor > /etc/apt/keyrings/agent-harbor.gpg"
  fi
  commands="${commands}
echo \"deb ${APT_REPO_URL} stable main\" > /etc/apt/sources.list.d/agent-harbor.list
apt-get update -qq
apt-get install -y ${PACKAGE_VARIANT} tmux"

  if ! confirm_package_manager_install "APT" "Debian/Ubuntu package manager" "$commands"; then
    warn "APT installation declined by user"
    return 1
  fi

  # GPG and repository configuration
  if [[ "$SKIP_GPG_CHECK" == "true" ]]; then
    warn "GPG check disabled - for testing only"
    local apt_options="[trusted=yes]"
  else
    info "Adding GPG key..."
    ensure_privileges
    mkdir -p /etc/apt/keyrings
    if ! fetch "${APT_REPO_URL}/gpg-key.asc" 2>/dev/null | ${SUDO} gpg --dearmor >/etc/apt/keyrings/agent-harbor.gpg; then
      warn "Failed to fetch or install GPG key from ${APT_REPO_URL}"
      warn "Repository may not exist yet, or there may be a network issue"
      return 1
    fi
    local apt_options="[signed-by=/etc/apt/keyrings/agent-harbor.gpg]"
  fi

  info "Adding APT repository..."
  if ! echo "deb ${apt_options} ${APT_REPO_URL} stable main" | ${SUDO} tee /etc/apt/sources.list.d/agent-harbor.list >/dev/null; then
    warn "Failed to add APT repository"
    return 1
  fi

  info "Updating package lists..."
  if ! ${SUDO} apt-get update -qq; then
    warn "Failed to update package lists - repository may be unavailable"
    return 1
  fi

  info "Installing ${PACKAGE_VARIANT} and tmux..."
  if ! ${SUDO} apt-get install -y "$PACKAGE_VARIANT" tmux; then
    warn "Failed to install ${PACKAGE_VARIANT} and tmux"
    return 1
  fi
}

# Install using DNF (Fedora)
install_dnf() {
  step "Installing via DNF"

  local SUDO
  SUDO=$(maybe_sudo)

  # Build command preview for confirmation
  local gpg_cmd=""
  if [[ "$SKIP_GPG_CHECK" != "true" ]]; then
    gpg_cmd="rpm --import ${YUM_REPO_URL}/gpg-key.asc
"
  fi

  local commands="tee /etc/yum.repos.d/agent-harbor.repo <<EOF
[agent-harbor]
name=Agent Harbor Repository
baseurl=${YUM_REPO_URL}
enabled=1
gpgcheck=$([[ "$SKIP_GPG_CHECK" == "true" ]] && echo "0" || echo "1")
gpgkey=${YUM_REPO_URL}/gpg-key.asc
metadata_expire=1h
type=rpm-md
EOF
${gpg_cmd}dnf install -y ${PACKAGE_VARIANT} tmux"

  if ! confirm_package_manager_install "DNF" "Fedora package manager" "$commands"; then
    warn "DNF installation declined by user"
    return 1
  fi

  if [[ "$SKIP_GPG_CHECK" == "true" ]]; then
    warn "GPG check disabled - for testing only"
    local gpg_check="0"
    local repo_gpg_check="0"
  else
    local gpg_check="1"
    local repo_gpg_check="1"
  fi

  info "Adding repository configuration..."
  ${SUDO} tee /etc/yum.repos.d/agent-harbor.repo >/dev/null <<EOF
[agent-harbor]
name=Agent Harbor Repository
baseurl=${YUM_REPO_URL}
enabled=1
gpgcheck=${gpg_check}
repo_gpgcheck=${repo_gpg_check}
gpgkey=${YUM_REPO_URL}/gpg-key.asc
metadata_expire=1h
type=rpm-md
EOF

  if [[ "$SKIP_GPG_CHECK" != "true" ]]; then
    info "Importing GPG key..."
    ${SUDO} rpm --import "${YUM_REPO_URL}/gpg-key.asc"
  fi

  info "Installing ${PACKAGE_VARIANT} and tmux..."
  ${SUDO} dnf install -y "$PACKAGE_VARIANT" tmux
}

# Install using YUM (RHEL, CentOS, Amazon Linux)
install_yum() {
  step "Installing via YUM"

  local SUDO
  SUDO=$(maybe_sudo)

  # Build command preview for confirmation
  local gpg_cmd=""
  if [[ "$SKIP_GPG_CHECK" != "true" ]]; then
    gpg_cmd="rpm --import ${YUM_REPO_URL}/gpg-key.asc
"
  fi

  local commands="tee /etc/yum.repos.d/agent-harbor.repo <<EOF
[agent-harbor]
name=Agent Harbor Repository
baseurl=${YUM_REPO_URL}
enabled=1
gpgcheck=$([[ "$SKIP_GPG_CHECK" == "true" ]] && echo "0" || echo "1")
gpgkey=${YUM_REPO_URL}/gpg-key.asc
metadata_expire=1h
EOF
${gpg_cmd}yum install -y ${PACKAGE_VARIANT} tmux"

  if ! confirm_package_manager_install "YUM" "RHEL/CentOS package manager" "$commands"; then
    warn "YUM installation declined by user"
    return 1
  fi

  if [[ "$SKIP_GPG_CHECK" == "true" ]]; then
    warn "GPG check disabled - for testing only"
    local gpg_check="0"
  else
    local gpg_check="1"
  fi

  info "Adding repository configuration..."
  ${SUDO} tee /etc/yum.repos.d/agent-harbor.repo >/dev/null <<EOF
[agent-harbor]
name=Agent Harbor Repository
baseurl=${YUM_REPO_URL}
enabled=1
gpgcheck=${gpg_check}
gpgkey=${YUM_REPO_URL}/gpg-key.asc
metadata_expire=1h
EOF

  if [[ "$SKIP_GPG_CHECK" != "true" ]]; then
    info "Importing GPG key..."
    ${SUDO} rpm --import "${YUM_REPO_URL}/gpg-key.asc"
  fi

  info "Installing ${PACKAGE_VARIANT} and tmux..."
  ${SUDO} yum install -y "$PACKAGE_VARIANT" tmux
}

# Install using APK (Alpine Linux)
install_apk() {
  step "Installing via APK"

  local SUDO
  SUDO=$(maybe_sudo)

  # Build command preview for confirmation
  local commands="echo \"${APK_REPO_URL}/@agent-harbor\" >> /etc/apk/repositories"
  if [[ "$SKIP_GPG_CHECK" != "true" ]]; then
    commands="${commands}
fetch ${APK_REPO_URL}/gpg-key.asc > /etc/apk/keys/agent-harbor@gpg-key.asc"
  fi
  commands="${commands}
apk update
apk add ${PACKAGE_VARIANT} tmux"

  if ! confirm_package_manager_install "APK" "Alpine Linux package manager" "$commands"; then
    warn "APK installation declined by user"
    return 1
  fi

  info "Adding APK repository..."
  echo "${APK_REPO_URL}/@agent-harbor" | ${SUDO} tee -a /etc/apk/repositories >/dev/null

  if [[ "$SKIP_GPG_CHECK" != "true" ]]; then
    info "Adding GPG key..."
    fetch "${APK_REPO_URL}/gpg-key.asc" | ${SUDO} tee /etc/apk/keys/agent-harbor@gpg-key.asc >/dev/null
  fi

  info "Updating package index..."
  ${SUDO} apk update

  info "Installing ${PACKAGE_VARIANT} and tmux..."
  ${SUDO} apk add "$PACKAGE_VARIANT" tmux
}

# Install using Pacman (Arch Linux)
install_pacman() {
  step "Installing via Pacman"

  local SUDO
  SUDO=$(maybe_sudo)

  # Build command preview for confirmation
  # Note: -Syu performs full system upgrade to avoid partial upgrade conflicts
  local commands="echo \"[agent-harbor]\\nSigLevel = Optional TrustAll\\nServer = ${ARCH_REPO_URL}/\$arch/\$repo\" >> /etc/pacman.conf
pacman -Syu
pacman -S --noconfirm ${PACKAGE_VARIANT} tmux"

  if ! confirm_package_manager_install "Pacman" "Arch Linux package manager" "$commands"; then
    warn "Pacman installation declined by user"
    return 1
  fi

  info "Adding repository configuration..."
  # Add to pacman.conf if not already present
  if ! grep -q "^\[agent-harbor\]" /etc/pacman.conf; then
    echo -e "\n[agent-harbor]\nSigLevel = Optional TrustAll\nServer = ${ARCH_REPO_URL}/\$arch/\$repo" | ${SUDO} tee -a /etc/pacman.conf >/dev/null
  fi

  info "Updating package database and upgrading system..."
  # Use -Syu to avoid partial upgrade conflicts (libgcc/libstdc++ vs gcc-libs)
  ${SUDO} pacman -Syu --noconfirm

  info "Installing ${PACKAGE_VARIANT} and tmux..."
  ${SUDO} pacman -S --noconfirm "$PACKAGE_VARIANT" tmux
}

# Install using Zypper (openSUSE)
install_zypper() {
  step "Installing via Zypper"

  local SUDO
  SUDO=$(maybe_sudo)

  # Build command preview for confirmation
  local commands="zypper addrepo -f ${YUM_REPO_URL} agent-harbor
zypper refresh
zypper install -y ${PACKAGE_VARIANT} tmux"

  if ! confirm_package_manager_install "Zypper" "openSUSE package manager" "$commands"; then
    warn "Zypper installation declined by user"
    return 1
  fi

  info "Adding repository..."
  ${SUDO} zypper addrepo -f "${YUM_REPO_URL}" agent-harbor

  info "Refreshing repositories..."
  ${SUDO} zypper refresh

  info "Installing ${PACKAGE_VARIANT} and tmux..."
  ${SUDO} zypper install -y "$PACKAGE_VARIANT" tmux
}

# Build the public macOS DMG URL for the selected architecture.
get_macos_dmg_url() {
  local arch="$1"
  local base_url="${MACOS_DMG_BASE_URL%/}"

  if [[ "${VERSION}" == "latest" ]]; then
    echo "${base_url}/latest/AgentHarbor-latest-${arch}.dmg"
  else
    local v="${VERSION#v}"
    echo "${base_url}/v${v}/AgentHarbor-${v}-${arch}.dmg"
  fi
}

# Install on macOS by downloading the signed/notarized DMG and deploying the
# .app bundle to /Applications. Homebrew is still used for tmux.
install_macos() {
  step "Installing on macOS (DMG app bundle)"

  # Homebrew is still used to install tmux dependency.
  if ! has_cmd brew; then
    die "Homebrew is required to install tmux on macOS. Please install it first:\n  /bin/bash -c \"\$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\""
  fi

  local arch
  arch=$(uname -m)
  case "$arch" in
  arm64 | aarch64) arch="arm64" ;;
  x86_64 | amd64) arch="x86_64" ;;
  *) die "Unsupported macOS architecture: ${arch}" ;;
  esac

  local dmg_url
  dmg_url=$(get_macos_dmg_url "$arch")

  # Map architecture to electron-builder convention for CLI binary path
  local electron_arch
  case "$arch" in
  arm64) electron_arch="arm64" ;;
  x86_64) electron_arch="x64" ;;
  esac

  local commands="brew install tmux
curl -fsSL ${dmg_url} -o /tmp/AgentHarbor.dmg
hdiutil attach /tmp/AgentHarbor.dmg
cp -R 'Agent Harbor.app' /Applications/
ln -sf '/Applications/Agent Harbor.app/Contents/Resources/cli/ah-${electron_arch}' /usr/local/bin/ah"

  if ! confirm_package_manager_install "macOS" "macOS native installer (DMG app bundle + Homebrew tmux)" "$commands"; then
    warn "macOS installation declined by user"
    return 1
  fi

  if brew list tmux >/dev/null 2>&1; then
    info "tmux already installed"
  else
    info "Installing tmux with Homebrew..."
    brew install tmux
  fi

  local tmpdir cleanup_cmd
  tmpdir=$(mktemp -d)
  cleanup_cmd=$(printf 'rm -rf %q' "$tmpdir")
  trap "$cleanup_cmd" RETURN

  local dmg_path="${tmpdir}/AgentHarbor.dmg"

  info "Downloading Agent Harbor DMG..."
  if ! fetch_to "$dmg_url" "$dmg_path"; then
    warn "Failed to download DMG: ${dmg_url}"
    return 1
  fi

  info "Mounting DMG..."
  local mount_point
  mount_point=$(hdiutil attach "$dmg_path" -nobrowse -readonly 2>/dev/null |
    awk -F'\t' '/Apple_HFS/ {print $NF}')

  if [[ -z "$mount_point" ]]; then
    warn "Failed to mount DMG"
    return 1
  fi

  # Find the .app bundle inside the mounted volume
  local app_path
  app_path=$(find "$mount_point" -maxdepth 1 -name "*.app" -type d | head -1)
  if [[ -z "$app_path" ]]; then
    hdiutil detach "$mount_point" -quiet || true
    warn "No .app bundle found in DMG"
    return 1
  fi

  local app_name
  app_name=$(basename "$app_path")
  local dest="/Applications/${app_name}"

  info "Installing ${app_name} to /Applications/..."
  if [[ -d "$dest" ]]; then
    info "Removing existing installation..."
  fi

  local SUDO
  SUDO=$(maybe_sudo)
  if [[ -w "/Applications" ]]; then
    rm -rf "$dest"
    cp -R "$app_path" "$dest"
  else
    ensure_privileges
    ${SUDO} rm -rf "$dest"
    ${SUDO} cp -R "$app_path" "$dest"
  fi

  info "Unmounting DMG..."
  hdiutil detach "$mount_point" -quiet || true

  # Create CLI symlink
  local cli_bin="${dest}/Contents/Resources/cli/ah-${electron_arch}"
  local symlink_dir="/usr/local/bin"

  if [[ -f "$cli_bin" ]]; then
    info "Creating CLI symlink..."
    if [[ ! -d "$symlink_dir" ]]; then
      if [[ -w "$(dirname "$symlink_dir")" ]]; then
        mkdir -p "$symlink_dir"
      else
        ensure_privileges
        ${SUDO} mkdir -p "$symlink_dir"
      fi
    fi

    if [[ -w "$symlink_dir" ]]; then
      ln -sf "$cli_bin" "${symlink_dir}/ah"
    else
      ensure_privileges
      ${SUDO} ln -sf "$cli_bin" "${symlink_dir}/ah"
    fi
    info "Symlinked ah → ${cli_bin}"
  else
    warn "CLI binary not found at ${cli_bin} — skipping symlink"
  fi

  info "Agent Harbor.app installed to /Applications/"

  # Print FSKit extension activation instructions
  echo ""
  info "To enable the AgentFS filesystem extension:"
  info "  1. Open System Settings → General → Login Items & Extensions"
  info "  2. Click the ⓘ next to \"File System Extensions\""
  info "  3. Enable \"AgentFSKitExtension\""
  echo ""

  # Offer to open System Settings
  if [[ -t 0 ]]; then
    printf '  Open System Settings now? [y/N] '
    read -r answer
    if [[ "$answer" =~ ^[Yy] ]]; then
      open "x-apple.systempreferences:com.apple.LoginItems-Settings.extension"
    fi
  fi
}

# ============================================================================
# Main installation dispatcher
# ============================================================================

install_native() {
  local distro
  distro=$(detect_os)

  case "$distro" in
  debian | ubuntu)
    install_apt
    ;;
  fedora)
    install_dnf
    ;;
  rhel | centos | rocky | almalinux | amzn)
    install_yum
    ;;
  alpine)
    install_apk
    ;;
  arch | manjaro)
    install_pacman
    ;;
  opensuse)
    install_zypper
    ;;
  darwin)
    install_macos
    ;;
  *)
    die "Unsupported distribution: $distro"
    ;;
  esac
}

# ============================================================================
# Internal installation function (can be called directly or used standalone)
# ============================================================================

# Run the native installation process. Can be called directly when sourced,
# or via main() when run standalone.
# Returns 0 on success, 1 on failure.
run_native_backend() {
  info "Agent Harbor Native Installer"
  info "============================="

  local platform distro
  platform=$(detect_platform)
  distro=$(detect_os)

  debug "Detected platform: $platform"
  debug "Detected distribution: $distro"

  info "Platform: $platform"
  info "Distribution: $distro"
  info "Package variant: $PACKAGE_VARIANT"

  # macOS doesn't need sudo for brew
  if [[ "$distro" != "darwin" ]]; then
    debug "Ensuring root privileges for non-macOS system..."
    ensure_privileges
  fi

  # Install
  debug "Starting native package installation..."
  if ! install_native; then
    error "Native installation failed"
    return 1
  fi

  # Return success - verification is handled by caller (dispatcher or main)
  return 0
}



# ============================================================================
# PART 4: Dispatcher and main entry point
# ============================================================================

VERSION="${VERSION:-latest}"
PACKAGE_VARIANT="${PACKAGE_VARIANT:-agent-harbor}"
INSTALL_MODE="${INSTALL_MODE:-}"
VERBOSE="${VERBOSE:-false}"

# Export NO_CONFIRM so it's picked up by confirm_danger()
NO_CONFIRM="${NO_CONFIRM:-false}"
export NO_CONFIRM

# Agent installation: "yes", "no", or empty (prompt interactively)
INSTALL_AGENTS="${INSTALL_AGENTS:-}"

# Debug logging
debug() {
  if [[ "$VERBOSE" == "true" ]]; then
    printf "%b[DEBUG]%b %s\n" "${BLUE}" "${NC}" "$*" >&2
  fi
}

print_banner() {
  printf "%b" "${BOLD}"
  printf "    _                    _     _   _            _               \n"
  printf "   / \\   __ _  ___ _ __ | |_  | | | | __ _ _ __| |__   ___  _ __ \n"
  printf "  / _ \\ / _\` |/ _ \\ '_ \\| __| | |_| |/ _\` | '__| '_ \\ / _ \\| '__|\n"
  printf " / ___ \\ (_| |  __/ | | | |_  |  _  | (_| | |  | |_) | (_) | |   \n"
  printf "/_/   \\_\\__, |\\___|_| |_|\\__| |_| |_|\\__,_|_|  |_.__/ \\___/|_|   \n"
  printf "        |___/                                                    \n"
  printf "%b" "${NC}"
  echo ""
  echo "Agent Harbor Installation Script"
  echo "https://agent-harbor.com"
  echo ""

  # Print build provenance if available
  if [[ -n "$BUILD_COMMIT_SHA" ]] || [[ -n "$BUILD_PR_URL" ]]; then
    [[ -n "$BUILD_PR_URL" ]] && echo "* PR: $BUILD_PR_URL"
    [[ -n "$BUILD_COMMIT_SHA" ]] && echo "* Commit: $BUILD_COMMIT_SHA"
    echo ""
  fi

  echo "For installation options and troubleshooting, visit:"
  echo "https://docs.agent-harbor.com/getting-started/installation"
  echo ""
}

usage() {
  cat <<EOF
Agent Harbor Installation Script

Usage:
  curl -fsSL https://install.agent-harbor.com | bash
  curl -fsSL https://install.agent-harbor.com | bash -s -- [OPTIONS]

Options:
  --nix               Force Nix-based installation
  --native            Force native package manager installation
  --auto              Auto-detect best method (default: prefer native)
  --with-agents       Install AI coding agents without prompting (Nix only)
  --without-agents    Skip AI coding agent installation (Nix only)
  --variant NAME      Package variant (agent-harbor, agent-harbor-cli, agent-harbor-fs)
  --version VERSION   Specific version to install (default: latest)
  --yes, -y           Skip confirmation prompts (same as --no-confirm)
  --no-confirm        Skip confirmation prompts (for automation)
  --verbose           Enable verbose debug output
  -h, --help          Show this help message

Environment Variables:
  NO_CONFIRM=true     Same as --yes / --no-confirm
  NO_COLOR=true       Disable colored output
EOF
}

parse_args() {
  while [[ $# -gt 0 ]]; do
    case "$1" in
    --nix) INSTALL_MODE="nix"; shift ;;
    --native) INSTALL_MODE="native"; shift ;;
    --auto) INSTALL_MODE="auto"; shift ;;
    --variant) PACKAGE_VARIANT="$2"; shift 2 ;;
    --version) VERSION="$2"; shift 2 ;;
    --with-agents) INSTALL_AGENTS="yes"; shift ;;
    --without-agents) INSTALL_AGENTS="no"; shift ;;
    --yes|-y) NO_CONFIRM="true"; shift ;;
    --no-confirm) NO_CONFIRM="true"; shift ;;
    --verbose) VERBOSE="true"; shift ;;
    -h|--help) usage; exit 0 ;;
    *) die "Unknown option: $1" ;;
    esac
  done
}

# Try Nix backend
# Returns 0 on success, 1 on failure
try_nix_install() {
  if ! run_nix_backend; then
    return 1
  fi
  info "Nix installation completed successfully"
  return 0
}

# Try native backend
# Returns 0 on success, 1 on failure
try_native_install() {
  info "Attempting native package installation..."
  if ! run_native_backend; then
    return 1
  fi
  info "Native installation completed successfully"
  return 0
}

# Auto-detect: prefer native, fallback to Nix
auto_install() {
  info "Auto-detecting best installation method..."

  # Ensure Nix is in PATH first (in case it was installed previously but PATH not set)
  ensure_nix_profile_in_path

  # 1. Existing Nix? Use it (developer fast path)
  debug "Checking if Nix is installed..."
  if check_nix_installed; then
    info "Nix detected - using Nix install"
    debug "Running try_nix_install..."
    if try_nix_install; then return 0; fi
    warn "Nix install failed, trying native..."
  else
    debug "Nix not found in PATH"
  fi

  # 2. Prefer native packages (no Nix needed for users)
  debug "Trying native installation..."
  # Suppress stderr in non-verbose mode to avoid cluttering output
  if [[ "$VERBOSE" == "true" ]]; then
    if try_native_install; then return 0; fi
  else
    if try_native_install 2>/dev/null; then return 0; fi
  fi
  debug "Native installation not available"

  # 3. Fallback to installing Nix
  warn "Native packages not available, will install via Nix"
  if try_nix_install; then return 0; fi

  die "Both installation methods failed"
}

main() {
  parse_args "$@"

  # Check if already installed (skips install if true)
  check_existing_installation || return 0

  print_banner

  # If no install mode specified, prompt interactively or fall back to auto
  if [[ -z "$INSTALL_MODE" ]]; then
    if ! is_non_interactive; then
      # Interactive terminal: show system checks and let user choose
      if ! prompt_install_method; then
        die "Installation method selection failed"
      fi
    else
      # Non-interactive (CI, piped): silently auto-detect
      INSTALL_MODE="auto"
    fi
  fi

  local confirm_status="yes"
  [[ "$NO_CONFIRM" == "true" ]] && confirm_status="no"
  info "Mode: $INSTALL_MODE | Version: $VERSION | Variant: $PACKAGE_VARIANT | Confirm: $confirm_status"

  case "$INSTALL_MODE" in
    nix)
      try_nix_install || die "Nix install failed"
      # Offer AI coding agent installation (Nix only)
      prompt_agent_install || true
      ;;
    native) try_native_install || die "Native install failed" ;;
    auto)
      auto_install || die "Installation failed"
      # Offer agents if Nix was used (auto may have chosen Nix)
      if [[ "$INSTALL_MODE" == "nix" ]] || check_nix_installed 2>/dev/null; then
        prompt_agent_install || true
      fi
      ;;
    *) die "Unknown mode: $INSTALL_MODE" ;;
  esac

  # Verify installation using shared function (don't fail if just PATH issue)
  verify_installation || true
}

main "$@"
