#!/usr/bin/env bash
# Debian 12/13: nvm + Node.js 22 + Codex CLI. Run as the intended login user.
set -Eeuo pipefail

usage() {
  cat <<'HELP'
Usage: bash install-codex-debian.sh [--mode auto|manual|full] [--http] [--configure-only]
  --mode auto       Workspace sandbox + automatic approval review (default).
  --mode manual     Workspace sandbox + approval requests routed to you.
  --mode full       No sandbox and no approval prompts.
  --http            Select the HTTPS/SSE provider, disabling WebSockets.
  --configure-only  Update config only; requires python3 and python3-tomlkit.
  -h, --help        Print this help.
Existing config is backed up before changes. Login and daemon restart are manual.
HELP
}

fail() { printf 'Error: %s\n' "$*" >&2; exit 1; }

install_dependencies() {
  local elevate=()
  if (( EUID != 0 )); then
    command -v sudo >/dev/null || fail 'sudo is required to install Debian packages.'
    elevate=(sudo)
  fi
  "${elevate[@]}" apt-get update
  "${elevate[@]}" apt-get install -y curl git ca-certificates build-essential \
    bubblewrap python3 python3-tomlkit
}

install_runtime() {
  local nvm_tag='v0.40.8' download_dir
  export NVM_DIR="${NVM_DIR:-$HOME/.nvm}"
  if [[ ! -s "$NVM_DIR/nvm.sh" ]]; then
    download_dir="$(mktemp -d)"
    if ! curl --fail --silent --show-error --location --retry 3 \
      --connect-timeout 15 --max-time 120 \
      "https://raw.githubusercontent.com/nvm-sh/nvm/${nvm_tag}/install.sh" \
      -o "$download_dir/install-nvm.sh"; then
      rm -rf -- "$download_dir"
      fail 'Could not download nvm.'
    fi
    if ! PROFILE=/dev/null bash "$download_dir/install-nvm.sh"; then
      rm -rf -- "$download_dir"
      fail 'nvm installation failed.'
    fi
    rm -rf -- "$download_dir"
  fi
  # nvm does not promise compatibility with nounset.
  set +u
  # shellcheck disable=SC1091
  . "$NVM_DIR/nvm.sh"
  nvm install 22
  nvm use 22
  nvm alias default 22
  set -u
  npm install -g @openai/codex@latest
  node --version
  npm --version
  codex --version
  if ! grep -Fq '# >>> 52ll.org Codex nvm >>>' "$HOME/.bashrc" 2>/dev/null; then
    {
      printf '\n# >>> 52ll.org Codex nvm >>>\n'
      printf 'export NVM_DIR=%q\n' "$NVM_DIR"
      # shellcheck disable=SC2016
      printf '[ ! -s "$NVM_DIR/nvm.sh" ] || . "$NVM_DIR/nvm.sh"\n'
      printf '# <<< 52ll.org Codex nvm <<<\n'
    } >> "$HOME/.bashrc"
  fi
}

write_config() {
  /usr/bin/python3 - "$1" "$2" "$3" <<'PY'
from pathlib import Path
from collections.abc import MutableMapping
import datetime, os, shutil, sys, tempfile
import tomlkit

path = Path(sys.argv[1]).expanduser().absolute()
mode, use_http = sys.argv[2], sys.argv[3] == "1"
if path.is_symlink():
    raise SystemExit("Config is a symlink; update its target manually.")
original = path.read_text() if path.exists() else ""
doc = tomlkit.parse(original)
if "default_permissions" in doc or "permissions" in doc:
    raise SystemExit("Named permission profiles exist; configure them manually before using this installer.")

def table(parent, key):
    if key not in parent:
        parent[key] = tomlkit.table()
    value = parent[key]
    if not isinstance(value, MutableMapping):
        raise SystemExit(f"{key} must be a TOML table; existing config was not changed.")
    return value

# Change only the requested keys and preserve unrelated config and comments.
doc["sandbox_mode"] = "danger-full-access" if mode == "full" else "workspace-write"
doc["approval_policy"] = "never" if mode == "full" else "on-request"
doc["approvals_reviewer"] = "auto_review" if mode == "auto" else "user"
tui = table(doc, "tui")
tui["fullscreen_transcript"] = False
tui["alternate_screen"] = "never"
if use_http:
    providers = table(doc, "model_providers")
    provider = table(providers, "openai_http")
    desired = {
        "name": "OpenAI HTTP",
        "base_url": "https://chatgpt.com/backend-api/codex",
        "wire_api": "responses",
        "requires_openai_auth": True,
        "supports_websockets": False,
    }
    if any(k not in desired or provider[k] != desired[k] for k in provider):
        raise SystemExit("An incompatible openai_http provider exists; config was not changed.")
    for key, value in desired.items():
        provider[key] = value
    doc["model_provider"] = "openai_http"
rendered = tomlkit.dumps(doc)
tomlkit.parse(rendered)
path.parent.mkdir(parents=True, exist_ok=True, mode=0o700)
if rendered == original:
    print(f"Config already matches: {path}")
    raise SystemExit(0)
if path.exists():
    stamp = datetime.datetime.now().strftime("%Y%m%d-%H%M%S-%f")
    backup = path.with_name(path.name + ".bak." + stamp)
    shutil.copy2(path, backup)
    backup.chmod(0o600)
    print(f"Config backup: {backup}")
fd, pending = tempfile.mkstemp(prefix=".config-", dir=path.parent)
try:
    with os.fdopen(fd, "w") as stream:
        stream.write(rendered)
    os.replace(pending, path)
finally:
    if os.path.exists(pending):
        os.unlink(pending)
print(f"Config saved: {path}")
PY
}

main() {
  local mode='auto' use_http=0 config_only=0
  while (( $# )); do
    case "$1" in
      --mode)
        (( $# >= 2 )) || fail '--mode needs auto, manual, or full.'
        mode="$2"; shift 2 ;;
      --http) use_http=1; shift ;;
      --configure-only) config_only=1; shift ;;
      -h|--help) usage; return ;;
      *) fail "Unknown argument: $1" ;;
    esac
  done
  [[ "$mode" =~ ^(auto|manual|full)$ ]] || fail 'Unknown mode.'
  [[ -r /etc/os-release ]] || fail 'Cannot identify this system.'
  # shellcheck disable=SC1091
  . /etc/os-release
  [[ "$ID" == debian ]] || fail 'This script targets Debian 12/13.'
  [[ "$VERSION_ID" == 12 || "$VERSION_ID" == 13 ]] || fail 'Use Debian 12 or 13.'
  case "$(uname -m)" in x86_64|aarch64) ;; *) fail 'Only amd64/arm64 are supported.' ;; esac
  if (( EUID == 0 )) && [[ -n "${SUDO_USER:-}" && "$SUDO_USER" != root ]]; then
    fail 'Run without sudo; the script uses sudo only for Debian packages.'
  fi
  local config_file="${CODEX_HOME:-$HOME/.codex}/config.toml"
  if (( ! config_only )); then
    install_dependencies
    install_runtime
  fi
  /usr/bin/python3 -c 'import tomlkit' 2>/dev/null || \
    fail 'Install python3-tomlkit first (apt-get install python3-tomlkit).'
  write_config "$config_file" "$mode" "$use_http"
  printf '\nDone. Reopen Bash or load nvm before running codex.\n'
  printf 'Then run: codex login --device-auth\n'
  printf 'Check login: codex login status\n'
  printf 'Mode: %s; config: %s\n' "$mode" "$config_file"
  if (( use_http )); then printf 'Model transport: HTTPS/SSE (WebSockets disabled).\n'; fi
  if [[ "$mode" == full ]]; then printf 'Full mode runs with your user permissions, without a sandbox or approval prompts.\n'; fi
}

if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
  main "$@"
fi
