#!/usr/bin/env bash
# trollbridge installer — fetches the latest release from
# github.com/dandriscoll/trollbridge, verifies SHA256, and installs
# to ~/.local/bin in user mode. No sudo, no system files touched.
#
# Usage:
#   curl -fsSL https://trollbridge.dev/install.sh | bash
#   curl -fsSL https://trollbridge.dev/install.sh | bash -s -- --uninstall
#
# Env vars:
#   TROLLBRIDGE_INSTALL_DIR  override install dir (default: ~/.local/bin)
#   TROLLBRIDGE_VERSION      pin a version (e.g. v0.5.7); default: latest
#
# Project: https://github.com/dandriscoll/trollbridge

if [ -z "${BASH_VERSION:-}" ]; then
  exec bash "$0" "$@" 2>/dev/null || { printf 'trollbridge install: error=bash_required. Re-run with: curl -fsSL https://trollbridge.dev/install.sh | bash\n' >&2; exit 1; }
fi

set -euo pipefail
IFS=$'\n\t'

REPO="dandriscoll/trollbridge"
INSTALL_DIR="${TROLLBRIDGE_INSTALL_DIR:-$HOME/.local/bin}"
BINARY_NAME="trollbridge"
TMPDIR_ROOT="${TMPDIR:-/tmp}"

err() {
  printf 'trollbridge install: %s\n' "$*" >&2
}

die() {
  err "$@"
  exit 1
}

require_cmd() {
  command -v "$1" >/dev/null 2>&1 || die "error=missing_${1//-/_}. install.sh needs '$1' on PATH. Install $1 (apt/brew/dnf) and re-run."
}

detect_platform() {
  local os arch uname_s uname_m
  uname_s="$(uname -s 2>/dev/null || echo unknown)"
  uname_m="$(uname -m 2>/dev/null || echo unknown)"
  case "$uname_s" in
    Linux)  os=linux ;;
    Darwin) os=darwin ;;
    *)      die "error=unsupported_os_arch os=$uname_s arch=$uname_m. trollbridge ships binaries for linux/macOS x amd64/arm64 only. Build from source: https://github.com/dandriscoll/trollbridge#build-from-source" ;;
  esac
  case "$uname_m" in
    x86_64|amd64) arch=amd64 ;;
    arm64|aarch64) arch=arm64 ;;
    *) die "error=unsupported_os_arch os=$uname_s arch=$uname_m. trollbridge ships binaries for linux/macOS x amd64/arm64 only. Build from source: https://github.com/dandriscoll/trollbridge#build-from-source" ;;
  esac
  printf '%s %s' "$os" "$arch"
}

resolve_version() {
  if [ -n "${TROLLBRIDGE_VERSION:-}" ]; then
    printf '%s' "$TROLLBRIDGE_VERSION"
    return
  fi
  local body tag
  if body="$(curl -fsSL --retry 3 --retry-delay 1 \
              "https://api.github.com/repos/${REPO}/releases/latest" 2>/dev/null)"; then
    tag="$(printf '%s' "$body" | sed -n 's/.*"tag_name":[[:space:]]*"\([^"]*\)".*/\1/p' | head -n1)"
    if [ -n "$tag" ]; then
      printf '%s' "$tag"
      return
    fi
  fi
  # Fallback: probe the redirect from /releases/latest
  local redirect
  redirect="$(curl -sILo /dev/null -w '%{redirect_url}' \
                "https://github.com/${REPO}/releases/latest" 2>/dev/null || true)"
  tag="${redirect##*/}"
  if [ -z "$tag" ] || [ "$tag" = "latest" ]; then
    die "error=network_fetch url=https://api.github.com/repos/${REPO}/releases/latest. Could not resolve latest version. Set TROLLBRIDGE_VERSION=vX.Y.Z to pin a version, or check https://github.com/${REPO}/releases."
  fi
  printf '%s' "$tag"
}

sha_check() {
  # Args: <expected_hex> <file>
  local expected="$1"
  local file="$2"
  local actual
  if command -v sha256sum >/dev/null 2>&1; then
    actual="$(sha256sum "$file" | awk '{print $1}')"
  elif command -v shasum >/dev/null 2>&1; then
    actual="$(shasum -a 256 "$file" | awk '{print $1}')"
  else
    die "error=missing_sha_tool. install.sh needs sha256sum or shasum on PATH. Install coreutils (Linux) or use the system shasum (macOS) and re-run."
  fi
  if [ "$actual" != "$expected" ]; then
    die "error=sha256_mismatch expected=${expected} actual=${actual} file=${file##*/}. Refusing to install. File a bug at https://github.com/${REPO}/issues with this output."
  fi
}

shell_rc_snippet() {
  # Print the right rc snippet(s) for the current shell.
  local shell_name
  shell_name="${SHELL##*/}"
  printf '\n  Add ~/.local/bin to your PATH:\n'
  case "$shell_name" in
    bash)
      printf '    echo '\''export PATH="$HOME/.local/bin:$PATH"'\'' >> ~/.bashrc && source ~/.bashrc\n' ;;
    zsh)
      printf '    echo '\''export PATH="$HOME/.local/bin:$PATH"'\'' >> ~/.zshrc && source ~/.zshrc\n' ;;
    fish)
      printf '    fish_add_path -U $HOME/.local/bin\n' ;;
    *)
      printf '    # Could not detect your shell. Pick the one that matches:\n'
      printf '    bash:  echo '\''export PATH="$HOME/.local/bin:$PATH"'\'' >> ~/.bashrc && source ~/.bashrc\n'
      printf '    zsh:   echo '\''export PATH="$HOME/.local/bin:$PATH"'\'' >> ~/.zshrc && source ~/.zshrc\n'
      printf '    fish:  fish_add_path -U $HOME/.local/bin\n' ;;
  esac
}

is_on_path() {
  case ":$PATH:" in
    *":$INSTALL_DIR:"*) return 0 ;;
    *) return 1 ;;
  esac
}

uninstall() {
  local target="$INSTALL_DIR/$BINARY_NAME"
  if [ -f "$target" ]; then
    rm -f "$target"
    printf 'trollbridge: removed %s\n' "$target"
  else
    printf 'trollbridge: nothing to remove at %s\n' "$target"
  fi
  printf '\nIf you previously added %s to your shell rc, you may want to remove that line.\n' "$INSTALL_DIR"
  exit 0
}

usage() {
  cat <<EOF
trollbridge installer

Usage:
  install.sh                fetch and install the latest release
  install.sh --uninstall    remove the installed binary
  install.sh --help         show this help

Environment:
  TROLLBRIDGE_INSTALL_DIR   override install dir (default: \$HOME/.local/bin)
  TROLLBRIDGE_VERSION       pin a version (default: latest release)

Source: https://github.com/dandriscoll/trollbridge
EOF
}

main() {
  case "${1:-}" in
    --uninstall)
      uninstall
      ;;
    --help|-h)
      usage
      exit 0
      ;;
    "") ;;
    *)
      err "error=unknown_arg arg=$1"
      usage
      exit 2
      ;;
  esac

  require_cmd curl
  require_cmd tar
  require_cmd uname
  require_cmd awk
  require_cmd sed
  if ! command -v sha256sum >/dev/null 2>&1 && ! command -v shasum >/dev/null 2>&1; then
    die "error=missing_sha_tool. install.sh needs sha256sum or shasum on PATH. Install coreutils (Linux) or use the system shasum (macOS) and re-run."
  fi

  IFS=' ' read -r OS ARCH <<<"$(detect_platform)"
  VERSION="$(resolve_version)"
  case "$VERSION" in v*) ;; *) VERSION="v${VERSION}" ;; esac

  local version_no_v="${VERSION#v}"
  local stem="trollbridge_v${version_no_v}_${OS}_${ARCH}"
  local tarball="${stem}.tar.gz"
  local base_url="https://github.com/${REPO}/releases/download/${VERSION}"
  local tarball_url="${base_url}/${tarball}"
  local sums_url="${base_url}/SHA256SUMS"

  local tmp
  tmp="$(mktemp -d "${TMPDIR_ROOT}/trollbridge-install.XXXXXX")"
  # Expand $tmp at trap-set time so the path is baked in even after main returns.
  trap "rm -rf '$tmp'" EXIT

  printf 'trollbridge: installing %s for %s/%s\n' "$VERSION" "$OS" "$ARCH"
  printf '  fetching %s\n' "$tarball_url"
  if ! curl -fSL --retry 3 --retry-delay 1 -o "$tmp/$tarball" "$tarball_url" 2>/dev/null; then
    die "error=network_fetch url=$tarball_url. Could not download the release tarball. Check that ${VERSION} exists at https://github.com/${REPO}/releases."
  fi

  printf '  fetching SHA256SUMS\n'
  if ! curl -fSL --retry 3 --retry-delay 1 -o "$tmp/SHA256SUMS" "$sums_url" 2>/dev/null; then
    die "error=network_fetch url=$sums_url. Could not download SHA256SUMS for ${VERSION}."
  fi

  local expected_sha
  expected_sha="$(awk -v t="$tarball" '$2==t || $2=="*"t {print $1; exit}' "$tmp/SHA256SUMS")"
  if [ -z "$expected_sha" ]; then
    die "error=sha256sums_missing_entry tarball=$tarball. The SHA256SUMS file for ${VERSION} does not contain an entry for ${tarball}. Release may be malformed; report at https://github.com/${REPO}/issues."
  fi

  printf '  verifying sha256\n'
  sha_check "$expected_sha" "$tmp/$tarball"

  printf '  extracting\n'
  if ! tar -xzf "$tmp/$tarball" -C "$tmp"; then
    die "error=extract_failed file=$tarball. Could not extract; tarball may be corrupted."
  fi

  if [ ! -x "$tmp/$stem/$BINARY_NAME" ]; then
    die "error=extract_failed file=$tarball. Tarball did not contain expected binary at $stem/$BINARY_NAME."
  fi

  if ! mkdir -p "$INSTALL_DIR"; then
    die "error=install_failed dir=$INSTALL_DIR. Could not create install directory. Set TROLLBRIDGE_INSTALL_DIR to a writable path."
  fi

  if ! install -m 0755 "$tmp/$stem/$BINARY_NAME" "$INSTALL_DIR/$BINARY_NAME" 2>/dev/null; then
    # `install` is missing on some minimal systems; fall back to cp+chmod.
    cp "$tmp/$stem/$BINARY_NAME" "$INSTALL_DIR/$BINARY_NAME" \
      || die "error=install_failed dir=$INSTALL_DIR. Could not write to $INSTALL_DIR/$BINARY_NAME."
    chmod 0755 "$INSTALL_DIR/$BINARY_NAME"
  fi

  printf '\ntrollbridge %s installed to %s/%s\n' "$VERSION" "$INSTALL_DIR" "$BINARY_NAME"

  if ! is_on_path; then
    shell_rc_snippet
  fi

  cat <<'EOF'

Next steps:
  trollbridge quickstart    fastest path: writes a minimal yaml + starts the proxy
  trollbridge init          interactive setup (default config in non-TTY)
  trollbridge --help        full command reference

To run trollbridge as a system daemon, install in user mode first, then ask
the binary to perform a daemon-mode upgrade (a separate, rooted setup step).

Docs and source: https://github.com/dandriscoll/trollbridge
EOF
}

main "$@"
