#!/usr/bin/env bash
# Venkel installer for macOS and Linux.
#
#   curl -fsSL https://install.venkel.dev | bash
#
# Prefer to read it before you run it?
#   curl -fsSL https://install.venkel.dev -o install.sh && less install.sh && bash install.sh
#
# What it does:
#   1. Installs uv (user-local, no sudo) if it is missing, plus a uv-managed Python 3.12
#   2. Downloads the Venkel wheel and verifies its checksum
#   3. Installs Venkel with `uv tool install` and adds ~/.local/bin to your shell's PATH for good
#   4. Installs the scanner set with Homebrew when Homebrew is available
#   5. Runs `venkel doctor`
#
# Nothing here uses sudo. Homebrew is optional: without it Venkel still installs, and
# `venkel doctor` lists the scanners you need to add by hand.
#
# Environment overrides (mostly for dev/testing):
#   VENKEL_INSTALL_BASE   where files are fetched from (default https://install.venkel.dev)
#   VENKEL_VERSION        version to install (default: the one this script shipped with)
#   VENKEL_NO_SCANNERS    set to skip the scanner step
#   NO_COLOR              set to disable ANSI colors
set -euo pipefail

VERSION="${VENKEL_VERSION:-0.1.0}"
BASE="${VENKEL_INSTALL_BASE:-https://install.venkel.dev}"
WHEEL="venkel-${VERSION}-py3-none-any.whl"
OS="$(uname -s)"

if [ -t 2 ] && [ -z "${NO_COLOR:-}" ]; then
  BOLD=$(printf '\033[1m'); RED=$(printf '\033[31m'); GREEN=$(printf '\033[32m'); YELLOW=$(printf '\033[33m'); RESET=$(printf '\033[0m')
else
  BOLD=''; RED=''; GREEN=''; YELLOW=''; RESET=''
fi
say()  { printf '\n%s==>%s %s\n' "$GREEN$BOLD" "$RESET" "$*" >&2; }
ok()   { printf '  %s✓%s %s\n' "$GREEN" "$RESET" "$*" >&2; }
warn() { printf '  %s!%s %s\n' "$YELLOW" "$RESET" "$*" >&2; }
die()  { printf '\n%s✗ %s%s\n\n' "$RED" "$*" "$RESET" >&2; exit 1; }
have() { command -v "$1" >/dev/null 2>&1; }

find_brew() {
  have brew && return 0
  for b in /opt/homebrew/bin/brew /usr/local/bin/brew /home/linuxbrew/.linuxbrew/bin/brew; do
    if [ -x "$b" ]; then eval "$("$b" shellenv)"; return 0; fi
  done
  return 1
}

# Put ~/.local/bin (where uv installs tools) on PATH now and for every new terminal,
# so the user never has to edit a shell file by hand. Idempotent: skips if the shell
# config already mentions it.
persist_path() {
  case ":$PATH:" in *":$HOME/.local/bin:"*) ;; *) export PATH="$HOME/.local/bin:$PATH" ;; esac
  local line='export PATH="$HOME/.local/bin:$PATH"' rc
  case "$(basename "${SHELL:-/bin/zsh}")" in
    zsh)  rc="${ZDOTDIR:-$HOME}/.zshrc" ;;
    bash) if [ "$OS" = "Darwin" ]; then rc="$HOME/.bash_profile"; else rc="$HOME/.bashrc"; fi ;;
    fish) mkdir -p "$HOME/.config/fish/conf.d"; rc="$HOME/.config/fish/conf.d/venkel.fish"; line='fish_add_path -g "$HOME/.local/bin"' ;;
    *)    rc="$HOME/.profile" ;;
  esac
  if ! grep -qsF '.local/bin' "$rc"; then
    printf '\n# Added by the Venkel installer: uv-installed tools (venkel) live here\n%s\n' "$line" >> "$rc"
    ok "added ~/.local/bin to PATH in ${rc/#$HOME/~}"
  fi
}

verify_checksums() {
  if have shasum; then shasum -a 256 -c SHA256SUMS --ignore-missing
  elif have sha256sum; then sha256sum -c SHA256SUMS --ignore-missing
  else die "Neither shasum nor sha256sum is available to verify the download."
  fi
}

main() {
  printf '\n%sVenkel %s installer%s\n' "$BOLD" "$VERSION" "$RESET" >&2
  case "$OS" in Darwin|Linux) ;; *) die "Unsupported OS: $OS. Venkel runs on macOS and Linux." ;; esac
  have curl || die "curl is required."

  # 1. uv, user-local. Homebrew is not required for this.
  say "uv"
  if ! have uv && [ -x "$HOME/.local/bin/uv" ]; then export PATH="$HOME/.local/bin:$PATH"; fi
  if ! have uv; then
    echo "  installing uv into ~/.local/bin (no sudo)" >&2
    curl -LsSf https://astral.sh/uv/install.sh | sh -s -- --quiet --no-modify-path
    export PATH="$HOME/.local/bin:$PATH"
  fi
  have uv || die "uv did not install. See https://docs.astral.sh/uv/getting-started/installation/ and re-run."
  ok "$(uv --version)"

  # 2. Python 3.12 managed by uv. Nothing on the system Python changes.
  say "Python 3.12 (managed by uv)"
  uv python install 3.12 --quiet
  ok "$(uv python find 3.12)"

  # 3. Download and verify Venkel.
  say "Downloading Venkel ${VERSION}"
  TMP="$(mktemp -d)"; trap 'rm -rf "$TMP"' EXIT
  cd "$TMP"
  curl -fsSLO "${BASE}/${WHEEL}" || die "Could not download ${BASE}/${WHEEL}"
  curl -fsSLO "${BASE}/SHA256SUMS"
  curl -fsSLO "${BASE}/Brewfile"
  verify_checksums >/dev/null || die "Checksum verification failed. Nothing was installed."
  ok "checksums verified"

  # 4. Install Venkel.
  say "Installing Venkel ${VERSION}"
  uv tool install --force --quiet --python 3.12 "./${WHEEL}"
  persist_path
  have venkel || die "venkel installed but could not be found on PATH. Please report this; run 'uv tool list' to confirm it is installed."
  ok "$(venkel --version)"

  # 5. Scanners. Homebrew installs five; Venkel fetches the two it pins by checksum.
  if [ -z "${VENKEL_NO_SCANNERS:-}" ]; then
    say "Scanners"
    if find_brew; then
      if brew bundle --file Brewfile --no-upgrade --quiet; then
        ok "scc, trivy, gitleaks, git-sizer, node"
      else
        warn "Homebrew could not install every scanner (is this account allowed to write to Homebrew?). 'venkel doctor' lists what is missing."
      fi
      have git || brew install --quiet git || true
      have gh  || brew install --quiet gh  || true
    else
      warn "Homebrew is not installed, so the scanners (scc, trivy, gitleaks, git-sizer, node) were skipped."
      warn "Install Homebrew from https://brew.sh, open a new terminal, and run this installer again; it will pick up where it left off."
    fi
    if venkel doctor --install >/dev/null 2>&1; then
      ok "Opengrep and jscpd at their locked versions"
    else
      warn "'venkel doctor --install' did not finish (it needs node for jscpd). Re-run it once node is installed."
    fi
  fi

  # 6. Doctor.
  say "Doctor"
  venkel doctor || warn "Some scanners are missing or drifted; see above. Missing tools are recorded as coverage gaps on every scan."

  cat >&2 <<MSG

${GREEN}${BOLD}Done.${RESET} Venkel ${VERSION} is installed.

  Open a new terminal window and type:  venkel
  The runbook starts at section 0:      ${BASE}/OPERATOR.md
  Something missing above? Fix it and run this installer again; it is safe to repeat.
MSG
}

main "$@"
