#!/usr/bin/env bash
# cli.johlem.net — jcli installer (Rust binary, glibc-dynamic)
# https://cli.johlem.net/tools/jcli/
#
# SECURITY: All downloads use HTTPS with curl certificate verification.
# Never modify this script to use HTTP or --insecure.
#
# This script is the canonical TEMPLATE for every Rust-binary tool in the
# suite. Per-tool installers are generated from it — only TOOL / VERSION
# change. To install jcli:
#   curl -fsSL https://cli.johlem.net/tools/jcli/install.sh | bash
set -euo pipefail

TOOL="jcli"
VERSION="latest"
BASE_URL="https://cli.johlem.net/tools/${TOOL}"
INSTALL_DIR="${HOME}/.local/bin"
DATA_DIR="${HOME}/.local/share/${TOOL}"

# ── Parse flags ────────────────────────────────────────────────────────────
FORCE=0
ROLLBACK=0
while [ $# -gt 0 ]; do
  case "$1" in
    --force)         FORCE=1 ;        shift ;;
    --pin-version=*) VERSION="${1#*=}"; shift ;;
    --pin-version)   VERSION="$2" ;   shift 2 ;;
    --rollback)      ROLLBACK=1 ;     shift ;;
    -h|--help)
      cat <<EOF
Install jcli — cli.johlem.net suite manager.
Usage: install.sh [--pin-version <V>] [--force] [--rollback]
EOF
      exit 0
      ;;
    *) shift ;;
  esac
done

# ── Detect architecture ────────────────────────────────────────────────────
detect_arch() {
  local arch
  arch="$(uname -m)"
  case "${arch}" in
    x86_64)  echo "x86_64-glibc" ;;
    aarch64) echo "aarch64-glibc" ;;
    *)
      echo "[ERROR] Unsupported architecture: ${arch}" >&2
      echo "[ERROR] Supported: x86_64, aarch64" >&2
      exit 1
      ;;
  esac
}

# ── Prereq check ───────────────────────────────────────────────────────────
check_prereqs() {
  local missing=0
  for cmd in curl sha256sum; do
    if ! command -v "${cmd}" &>/dev/null; then
      echo "[ERROR] Required command not found: ${cmd}" >&2
      missing=1
    fi
  done
  [ "${missing}" -eq 0 ] || exit 1
}

# ── Resolve "latest" → concrete version ────────────────────────────────────
resolve_version() {
  if [ "${VERSION}" = "latest" ]; then
    local fetched
    fetched="$(curl -fsSL --max-time 10 "${BASE_URL}/version" 2>/dev/null || true)"
    if [ -z "${fetched}" ]; then
      echo "[ERROR] Failed to fetch latest version from ${BASE_URL}/version" >&2
      exit 1
    fi
    VERSION="${fetched}"
  fi
}

# ── Rollback path (early exit; no download) ────────────────────────────────
do_rollback() {
  local bak="${INSTALL_DIR}/${TOOL}.bak"
  local dest="${INSTALL_DIR}/${TOOL}"
  if [ ! -f "${bak}" ]; then
    echo "[ERROR] No backup at ${bak}" >&2
    exit 3
  fi
  mv "${bak}" "${dest}"
  echo "[${TOOL}] Rolled back to previous version."
  exit 0
}

# ── Download + verify ──────────────────────────────────────────────────────
download_binary() {
  local arch="$1"
  local binary_name="${TOOL}-v${VERSION}-linux-${arch}"
  local binary_url="${BASE_URL}/releases/${binary_name}"
  local checksum_url="${binary_url}.sha256"
  local sig_url="${binary_url}.sig"
  local pub_key_url="https://cli.johlem.net/johlem-release.pub"

  local tmp_dir
  tmp_dir="$(mktemp -d)"
  local tmp_bin="${tmp_dir}/${TOOL}"
  local tmp_sum="${tmp_dir}/${TOOL}.sha256"

  echo "[${TOOL}] Downloading v${VERSION} (${arch})..."
  if ! curl -fsSL --progress-bar "${binary_url}" -o "${tmp_bin}"; then
    echo "[ERROR] Download failed: ${binary_url}" >&2
    rm -rf "${tmp_dir}"
    exit 1
  fi

  # ── SHA-256 ──────────────────────────────────────────────────────────────
  echo "[${TOOL}] Verifying checksum..."
  if ! curl -fsSL "${checksum_url}" -o "${tmp_sum}"; then
    echo "[ERROR] Checksum fetch failed: ${checksum_url}" >&2
    rm -rf "${tmp_dir}"
    exit 1
  fi
  local expected_hash
  expected_hash="$(awk '{print $1}' "${tmp_sum}")"
  if ! echo "${expected_hash}" | grep -qE '^[0-9a-f]{64}$'; then
    echo "[ERROR] Checksum file malformed: ${checksum_url}" >&2
    rm -rf "${tmp_dir}"
    exit 1
  fi
  local actual_hash
  actual_hash="$(sha256sum "${tmp_bin}" | awk '{print $1}')"
  if [ "${expected_hash}" != "${actual_hash}" ]; then
    echo "[ERROR] Checksum mismatch!" >&2
    echo "[ERROR]   Expected: ${expected_hash}" >&2
    echo "[ERROR]   Got:      ${actual_hash}" >&2
    rm -rf "${tmp_dir}"
    exit 1
  fi
  echo "[${TOOL}] SHA-256 verified."

  # ── Ed25519 signature (optional but strongly recommended) ───────────────
  local signify_cmd=""
  if command -v signify &>/dev/null; then
    signify_cmd="signify"
  elif command -v signify-openbsd &>/dev/null; then
    signify_cmd="signify-openbsd"
  fi
  if [ -n "${signify_cmd}" ]; then
    local sig_file="${tmp_dir}/${TOOL}.sig"
    local pub_file="${tmp_dir}/johlem-release.pub"
    if curl -fsSL "${sig_url}" -o "${sig_file}" 2>/dev/null \
       && curl -fsSL "${pub_key_url}" -o "${pub_file}" 2>/dev/null; then
      if ! "${signify_cmd}" -V -p "${pub_file}" -m "${tmp_bin}" -x "${sig_file}" >/dev/null 2>&1; then
        echo "[ERROR] SIGNATURE VERIFICATION FAILED — the binary may have been tampered with." >&2
        rm -rf "${tmp_dir}"
        exit 1
      fi
      echo "[${TOOL}] Ed25519 signature verified."
    else
      echo "[WARNING] Signature or public key unavailable — skipping signify verification."
    fi
  else
    echo "[WARNING] signify not found — skipping Ed25519 verification."
    echo "[WARNING] Install signify for full security: apt install signify-openbsd"
  fi

  # Return via global instead of stdout capture. Status messages above
  # also write to stdout, so `tmp_bin=$(download_binary ...)` would capture
  # ALL of them (multi-line), and `chmod $tmp_bin` would fail with
  # "cannot access '[jcli] Downloading...'". Caller reads RESULT_BIN.
  RESULT_BIN="${tmp_bin}"
}

# ── Install with backup-on-replace ─────────────────────────────────────────
install_binary() {
  local tmp_bin="$1"
  mkdir -p "${INSTALL_DIR}" "${DATA_DIR}"

  if [ -f "${INSTALL_DIR}/${TOOL}" ]; then
    local backup="${INSTALL_DIR}/${TOOL}.bak"
    mv "${INSTALL_DIR}/${TOOL}" "${backup}"
    echo "[${TOOL}] Previous version backed up to ${backup}"
  fi

  chmod +x "${tmp_bin}"
  mv "${tmp_bin}" "${INSTALL_DIR}/${TOOL}"
  echo "${VERSION}" > "${DATA_DIR}/.installed_version"
  echo "[${TOOL}] Installed to ${INSTALL_DIR}/${TOOL}"
}

# ── PATH hint ──────────────────────────────────────────────────────────────
check_path() {
  if ! echo "${PATH}" | grep -q "${HOME}/.local/bin"; then
    cat >&2 <<EOF

[WARNING] ${HOME}/.local/bin is not in your PATH.
  Add this to your shell config (~/.bashrc, ~/.zshrc, ~/.profile):

    export PATH="\$HOME/.local/bin:\$PATH"

  Or for NixOS, add to ~/.config/nixpkgs/home.nix:
    home.sessionPath = [ "\$HOME/.local/bin" ];

EOF
  fi
}

# ── Main ───────────────────────────────────────────────────────────────────
main() {
  echo "==================================="
  echo " cli.johlem.net — ${TOOL} installer"
  echo "==================================="

  [ "${ROLLBACK}" -eq 1 ] && do_rollback

  check_prereqs
  resolve_version

  local current_ver=""
  if [ -f "${DATA_DIR}/.installed_version" ]; then
    current_ver="$(cat "${DATA_DIR}/.installed_version")"
  fi
  if [ "${current_ver}" = "${VERSION}" ] && [ "${FORCE}" -eq 0 ]; then
    echo "[${TOOL}] Already at v${VERSION}. Use --force to reinstall."
    exit 0
  fi

  local arch
  arch="$(detect_arch)"
  RESULT_BIN=""
  download_binary "${arch}"
  install_binary "${RESULT_BIN}"
  check_path

  echo ""
  echo "[${TOOL}] Installation complete — v${VERSION}"
  echo "[${TOOL}] Run: ${TOOL} --help"
  echo ""
}

main
