#!/usr/bin/env bash
# Create the Python environment and fetch the pinned, checksum-verified tunnel-client.
set -euo pipefail

ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
VENDOR="${ROOT}/vendor"
VENV="${ROOT}/venv"
LOCK="${ROOT}/requirements.lock.txt"
TUNNEL_CLIENT_VERSION="v0.0.11"
TUNNEL_CLIENT_ASSET="tunnel-client-${TUNNEL_CLIENT_VERSION}-linux-amd64.zip"
TUNNEL_CLIENT_SHA256="29adfe5c1399dfb9fda9383f230c324355912f50dc36e2e416b1f1322317b3c4"
TUNNEL_CLIENT_BIN_SHA256="c79ad91d929f50cb1676c4fcbce937c81b1854ec37ca758118c2d78a373c431f"

BIN_DIR="${GPTBRIDGE_BIN_DIR:-${HOME}/.local/bin}"
# sw drives gptbridge but lives with the other harness wrappers.
SW="${ROOT}/../harness/wrappers/sw.sh"

DRY_RUN=0
LINKS_ONLY=0
for arg in "$@"; do case "$arg" in --dry-run) DRY_RUN=1;; --links-only) LINKS_ONLY=1;; *) echo "install: unknown argument: $arg" >&2; exit 2;; esac; done

link_commands() {
  # Preflight every source and destination before changing any link.  Refusing a
  # regular target prevents deployment from overwriting an operator-owned command.
  local name source target tmp
  mkdir -p "$BIN_DIR"
  for name in ask-gpt solwebd solwebctl factory-gpt install-ccr-provider sw; do
    source="${ROOT}/bin/${name}"; [[ "$name" == sw ]] && source="$SW"
    [[ -f "$source" && -x "$source" ]] || die "missing or non-executable source: $source"
    target="$BIN_DIR/$name"
    [[ ! -e "$target" || -L "$target" ]] || die "refusing non-symlink target: $target"
  done
  for name in ask-gpt solwebd solwebctl factory-gpt install-ccr-provider sw; do
    source="${ROOT}/bin/${name}"; [[ "$name" == sw ]] && source="$SW"
    target="$BIN_DIR/$name"; tmp="$BIN_DIR/.${name}.link.$$"
    ln -s "$source" "$tmp" || die "cannot stage link: $target"
    mv -Tf "$tmp" "$target" || die "cannot install link: $target"
  done
  say "linked ask-gpt, solwebd, solwebctl, factory-gpt, install-ccr-provider, sw into ${BIN_DIR}"
}

say() { echo "install: $*"; }
die() { echo "install: $*" >&2; exit 1; }

if [ "$LINKS_ONLY" = 1 ]; then
  if [ "$DRY_RUN" = 1 ]; then
    say "would link ask-gpt, solwebd, solwebctl, factory-gpt, install-ccr-provider, sw into ${BIN_DIR}"
    exit 0
  fi
  link_commands
  exit 0
fi

[ "$(uname -m)" = "x86_64" ] || die "no pinned tunnel-client asset for $(uname -m)"
command -v python3 >/dev/null || die "python3 not found"
command -v bwrap >/dev/null \
  || die "bubblewrap not found; gptbridge sandboxes every command with bwrap (apt install bubblewrap)"

if [ "$DRY_RUN" = 1 ]; then
  say "would create ${VENV} from ${LOCK} with --require-hashes"
  say "would fetch ${TUNNEL_CLIENT_ASSET} into ${VENDOR} and verify sha256 ${TUNNEL_CLIENT_SHA256}"
  say "would link ask-gpt, solwebd, solwebctl, factory-gpt, install-ccr-provider, sw into ${BIN_DIR}"
  exit 0
fi

if [ ! -x "${VENV}/bin/python" ]; then
  say "creating ${VENV}"
  python3 -m venv "$VENV"
fi
# --require-hashes pins every transitive dependency to a known artifact, so a
# compromised or yanked-and-replaced release on the index cannot be installed.
"${VENV}/bin/pip" install --quiet --disable-pip-version-check --require-virtualenv \
  --require-hashes -r "$LOCK"

verify_binary() {
  local actual
  actual="$(sha256sum "${VENDOR}/tunnel-client" | cut -d' ' -f1)"
  [ "$actual" = "$TUNNEL_CLIENT_BIN_SHA256" ] \
    || die "vendored tunnel-client does not match the pinned build (${actual}); delete ${VENDOR} and re-run"
}

if [ -x "${VENDOR}/tunnel-client" ]; then
  # Verified on every run, not only after the download: the archive checksum says
  # nothing about a binary that was swapped on disk afterwards.
  verify_binary
else
  mkdir -p "$VENDOR"
  workdir="$(mktemp -d)"
  trap 'rm -rf "$workdir"' EXIT
  say "fetching openai/tunnel-client ${TUNNEL_CLIENT_VERSION}"
  curl -fsSL -o "${workdir}/${TUNNEL_CLIENT_ASSET}" \
    "https://github.com/openai/tunnel-client/releases/download/${TUNNEL_CLIENT_VERSION}/${TUNNEL_CLIENT_ASSET}"
  actual="$(sha256sum "${workdir}/${TUNNEL_CLIENT_ASSET}" | cut -d' ' -f1)"
  [ "$actual" = "$TUNNEL_CLIENT_SHA256" ] \
    || die "checksum mismatch for ${TUNNEL_CLIENT_ASSET}: expected ${TUNNEL_CLIENT_SHA256}, got ${actual}"
  unzip -oq "${workdir}/${TUNNEL_CLIENT_ASSET}" -d "$VENDOR"
  chmod +x "${VENDOR}/tunnel-client"
  verify_binary
fi

link_commands

say "ready — run '${ROOT}/bin/gptbridge doctor'"
