#!/bin/sh
# Halton Meter public installer — "bootstrap now, binaries later".
#
#   curl -fsSL https://get.haltonmeter.com/install.sh | sh
#   curl -fsSL https://get.haltonmeter.com/install.sh | sh -s -- --version 0.5.0
#
# This is the PUBLIC install path. It does NOT download a prebuilt binary and
# does NOT verify a SHA-256 (that is the enterprise installer, packaging/
# enterprise/install.sh). Instead it:
#   1. installs uv (https://astral.sh/uv) if it is missing,
#   2. `uv tool install halton-meter` from PyPI (isolated, brings its own
#      Python interpreter — no system Python required),
#   3. runs `halton-meter init` (unless --skip-init).
#
# Zero workflow disruption: this only installs + configures the meter. The
# meter's edge fails open, so traffic always flows through to the upstream
# provider even if the daemon is off. Nothing here breaks your API calls.
#
# POSIX sh (not bash) — piped installers run under whatever /bin/sh is.
# macOS + Linux. Windows: use the PowerShell one-liner (see usage()).
set -eu

# --- defaults / env overrides ----------------------------------------------
# Env overrides let CI / dev drive the script without editing argv (a piped
# `curl ... | sh` cannot take positional flags cleanly).
SKIP_UV="${HALTON_METER_SKIP_UV:-0}"
SKIP_INIT="${HALTON_METER_SKIP_INIT:-0}"
VERSION="${HALTON_METER_VERSION:-}"
PACKAGE_SPEC="${HALTON_METER_PACKAGE_SPEC:-halton-meter}"
INDEX_URL="${HALTON_METER_INDEX_URL:-}"
INIT_MODE=""

usage() {
    echo "usage: install.sh [--version X.Y.Z] [--skip-init] [--apps|--full]"
    echo ""
    echo "flags:"
    echo "  --version X.Y.Z  pin the halton-meter release to install"
    echo "  --skip-init      install the CLI but do not run 'halton-meter init'"
    echo "  --apps           pass --apps to 'halton-meter init' (metered apps only)"
    echo "  --full           pass --full to 'halton-meter init' (adds browser HTTPS)"
    echo "  -h, --help       show this help and exit"
    echo ""
    echo "env overrides (equivalents for piped 'curl ... | sh' use):"
    echo "  HALTON_METER_VERSION=X.Y.Z     same as --version"
    echo "  HALTON_METER_SKIP_INIT=1       same as --skip-init"
    echo "  HALTON_METER_SKIP_UV=1         assume uv is present; never install it"
    echo "  HALTON_METER_PACKAGE_SPEC=...  override the uv install target"
    echo "                                 (e.g. a local .whl path or 'halton-meter==X.Y.Z')"
    echo "  HALTON_METER_INDEX_URL=...     install from this index instead of PyPI"
    echo "  HALTON_METER_KEEP_PROXY=1      keep proxy env vars (default drops loopback-only)"
}

# --- argument parsing -------------------------------------------------------
while [ $# -gt 0 ]; do
    case "$1" in
        --version)   VERSION="${2:?--version needs a value}"; shift 2 ;;
        --skip-init) SKIP_INIT=1; shift ;;
        --apps)      INIT_MODE=apps; shift ;;
        --full)      INIT_MODE=full; shift ;;
        -h|--help)   usage; exit 0 ;;
        *) echo "error: unknown argument: $1" >&2; usage >&2; exit 2 ;;
    esac
done

# A bare version pin with the default package name becomes a versioned spec.
if [ -n "$VERSION" ] && [ "$PACKAGE_SPEC" = "halton-meter" ]; then
    PACKAGE_SPEC="halton-meter==${VERSION}"
fi

# --- OS / arch detect -------------------------------------------------------
OS="$(uname -s)"
ARCH="$(uname -m)"
case "$OS" in
    Darwin) OS=macos ;;
    Linux)  OS=linux ;;
    *)
        echo "error: unsupported platform: $OS" >&2
        echo "Windows: use the PowerShell one-liner:" >&2
        echo "    irm https://get.haltonmeter.com/install.ps1 | iex" >&2
        echo "Anything else: contact operator@haltonlabs.com" >&2
        exit 1
        ;;
esac
# uv provisions its own interpreter, so we do not hard-reject on arch — just
# echo it for diagnostics if an install ever misbehaves.
echo "==> halton-meter public installer (${OS}, arch ${ARCH})"

# --- helpers ----------------------------------------------------------------
# Prepend a directory to PATH for THIS script's scope if it exists and is not
# already present. Used to make a freshly-installed uv (and the uv tool bin
# dir) visible to the rest of the script without a new shell.
ensure_on_path() {
    _dir="$1"
    [ -n "$_dir" ] || return 0
    [ -d "$_dir" ] || return 0
    case ":${PATH}:" in
        *":${_dir}:"*) : ;;
        *) PATH="${_dir}:${PATH}"; export PATH ;;
    esac
}

# --- stale-CA / stale-proxy pre-emption -------------------------------------
# A CA env var left over from a previous certifi bundle (since deleted) makes
# uv/curl abort with "Could not find a suitable TLS CA certificate bundle".
# A half-configured meter edge that is currently down would break our own
# curl/uv if we honoured its proxy vars. Neutralise both FOR THIS SCRIPT ONLY;
# we never touch the user's shell. See INSTALL.md "Install / upgrade gotchas".
UNSET_LIST=""
_val=""
_pval=""
_dropped_proxy=""
for _name in CURL_CA_BUNDLE SSL_CERT_FILE REQUESTS_CA_BUNDLE \
             NODE_EXTRA_CA_CERTS GIT_SSL_CAINFO AWS_CA_BUNDLE; do
    eval "_val=\${$_name:-}"
    if [ -n "$_val" ] && [ ! -e "$_val" ]; then
        unset "$_name"
        UNSET_LIST="${UNSET_LIST} ${_name}"
    fi
done
# Only drop proxy vars that point at a LOOPBACK host (the meter's own edge,
# which may be half-configured / down). A remote/corporate proxy is preserved —
# we may need it to reach PyPI. Override entirely with HALTON_METER_KEEP_PROXY=1.
if [ "${HALTON_METER_KEEP_PROXY:-0}" != 1 ]; then
    _dropped_proxy=""
    for _pv in HTTPS_PROXY HTTP_PROXY ALL_PROXY https_proxy http_proxy all_proxy; do
        eval "_pval=\${$_pv:-}"
        case "$_pval" in
            *localhost*|*127.0.0.1*|*"[::1]"*)
                unset "$_pv" 2>/dev/null || true
                _dropped_proxy="${_dropped_proxy} ${_pv}"
                ;;
        esac
    done
    if [ -n "$_dropped_proxy" ]; then
        echo "==> dropped loopback proxy var(s) for this install:${_dropped_proxy}"
        echo "    (they point at the meter's own edge, which may be down mid-install;"
        echo "     your API traffic is unaffected). Keep them with HALTON_METER_KEEP_PROXY=1."
    fi
fi

if [ -n "$UNSET_LIST" ]; then
    echo "==> cleared stale CA env var(s) for this install:${UNSET_LIST}"
    echo "    (they pointed at files that no longer exist)"
    echo "    If a later MANUAL command fails with a TLS CA error, run this in YOUR shell:"
    echo "        unset CURL_CA_BUNDLE SSL_CERT_FILE REQUESTS_CA_BUNDLE NODE_EXTRA_CA_CERTS \\"
    echo "              GIT_SSL_CAINFO AWS_CA_BUNDLE"
fi

# --- ensure uv --------------------------------------------------------------
if [ "$SKIP_UV" = 1 ]; then
    echo "==> HALTON_METER_SKIP_UV=1 set; assuming uv is already present"
elif command -v uv >/dev/null 2>&1; then
    echo "==> uv already installed ($(uv --version 2>/dev/null || echo unknown))"
else
    echo "==> installing uv (astral.sh)"
    curl -LsSf https://astral.sh/uv/install.sh | sh
fi

# Make a just-installed uv visible without a new shell. uv 0.8 installs to
# $HOME/.local/bin by default, honouring XDG_BIN_HOME / CARGO_HOME.
ensure_on_path "${XDG_BIN_HOME:-}"
if [ -n "${CARGO_HOME:-}" ]; then
    ensure_on_path "${CARGO_HOME}/bin"
fi
ensure_on_path "${HOME}/.local/bin"

if ! command -v uv >/dev/null 2>&1; then
    echo "error: uv is not on PATH after install." >&2
    echo "Open a new terminal (so uv's env is loaded) and re-run this installer," >&2
    echo "or install uv manually: https://docs.astral.sh/uv/getting-started/installation/" >&2
    exit 1
fi

# --- install / upgrade halton-meter ----------------------------------------
# uv tool install brings its own Python interpreter, so no system Python is
# required. Idempotent + re-runnable: already-installed => force/upgrade.
if uv tool list 2>/dev/null | grep -q '^halton-meter '; then
    ALREADY=1
else
    ALREADY=0
fi

if [ "$ALREADY" = 1 ] && [ -z "$VERSION" ] && [ -z "$INDEX_URL" ] && \
   [ "$PACKAGE_SPEC" = "halton-meter" ]; then
    # Plain in-place upgrade to the latest published release.
    set -- tool upgrade halton-meter
else
    # Fresh install, a pinned version, a custom index, or a custom spec:
    # (re)install the exact spec. --force makes it idempotent when present.
    if [ "$ALREADY" = 1 ]; then
        set -- tool install --force "$PACKAGE_SPEC"
    else
        set -- tool install "$PACKAGE_SPEC"
    fi
    # --index is the current uv 0.8 flag (-i/--index-url is deprecated).
    if [ -n "$INDEX_URL" ]; then
        set -- "$@" --index "$INDEX_URL"
    fi
fi
echo "==> uv $*"
if ! uv "$@"; then
    echo "error: '${*}' failed. halton-meter was NOT installed." >&2
    echo "Your existing API traffic is unaffected (this only installs software)." >&2
    exit 1
fi

# --- resolve the installed executable --------------------------------------
# Put the uv tool bin dir on PATH so `command -v halton-meter` resolves.
if UV_TOOL_BIN="$(uv tool dir --bin 2>/dev/null)"; then
    ensure_on_path "$UV_TOOL_BIN"
else
    ensure_on_path "${HOME}/.local/bin"
fi

HM_BIN="$(command -v halton-meter || true)"
if [ -z "$HM_BIN" ]; then
    echo "error: halton-meter installed but not found on PATH." >&2
    echo "It usually lives in: ${UV_TOOL_BIN:-$HOME/.local/bin}" >&2
    echo "Add that directory to your PATH, open a new terminal, then run 'halton-meter init'." >&2
    exit 1
fi
echo "==> installed: $("$HM_BIN" --version 2>/dev/null || echo 'halton-meter (version check failed)')"

# --- PATH guidance ----------------------------------------------------------
HM_BIN_DIR="$(dirname "$HM_BIN")"
case ":${PATH}:" in
    *":${HM_BIN_DIR}:"*) : ;;
    *)
        echo ""
        echo "Add halton-meter to your PATH in new shells:"
        echo "    echo 'export PATH=\"${HM_BIN_DIR}:\$PATH\"' >> ~/.zshrc"
        ;;
esac

# --- init -------------------------------------------------------------------
if [ "$SKIP_INIT" = 1 ]; then
    echo ""
    echo "halton-meter installed (init skipped)."
    if [ -n "$INIT_MODE" ]; then
        echo "Finish setup with: ${HM_BIN} init --${INIT_MODE}"
    else
        echo "Finish setup with: ${HM_BIN} init"
    fi
    exit 0
fi

echo ""
echo "==> running halton-meter init"
echo "    This MAY PROMPT FOR YOUR PASSWORD to trust the inspection certificate."
if [ -n "$INIT_MODE" ]; then
    set -- init "--${INIT_MODE}"
else
    set -- init
fi
if "$HM_BIN" "$@"; then
    echo ""
    echo "halton-meter installed and initialised."
    echo ""
    echo "Next steps:"
    echo "  1. Open a NEW terminal (or run 'exec zsh') so the env block loads."
    echo "  2. If an already-running app shows ConnectionRefused, restart it:"
    echo "         pkill -9 -f \"claude-code\"; exec zsh"
    echo "     (it baked in the old env before init ran; the edge fails open,"
    echo "      so your traffic is never blocked — the app just needs the new env)."
    echo "  3. Verify:  halton-meter status   &&   halton-meter report"
else
    # Fail open: the CLI IS installed. Do not exit non-zero in a way that
    # reads like the install failed — just tell the user how to finish init.
    echo ""
    echo "halton-meter is installed, but 'halton-meter init' did not complete." >&2
    if [ -n "$INIT_MODE" ]; then
        echo "Re-run it manually: ${HM_BIN} init --${INIT_MODE}" >&2
    else
        echo "Re-run it manually: ${HM_BIN} init" >&2
    fi
fi
