#!/bin/sh

set -eu

BRIDGE_VERSION="0.1.1"
UV_VERSION="0.13.1"
UV_INSTALLER_SHA256="7c482d409673a53f4d9bd34ae95c9166be3b8d89ca82f27dd7bca3cab457afff"
UV_INSTALLER_URL="https://github.com/astral-sh/uv/releases/download/${UV_VERSION}/uv-installer.sh"
SERVER_URL="https://api.yantraxa.com"

say() {
  printf '%s\n' "$*"
}

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

usage() {
  say "Usage: install.sh [--dry-run] [--uninstall] [--no-service] [claude-code|codex-cli|ollama]"
  say "  --no-service  Pair, but don't start the bridge at login."
}

assert_safe_home() {
  [ -n "${HOME:-}" ] || die 'HOME is not set.'
  [ "$HOME" != "/" ] || die 'Refusing to use / as HOME.'
  case "$HOME" in
    /*) ;;
    *) die 'HOME must be an absolute path.' ;;
  esac
}

find_sha256_command() {
  if command -v sha256sum >/dev/null 2>&1; then
    SHA256_COMMAND="sha256sum"
  elif command -v shasum >/dev/null 2>&1; then
    SHA256_COMMAND="shasum -a 256"
  else
    die 'A SHA-256 tool is required (sha256sum or shasum). Nothing was installed.'
  fi
}

verify_sha256() {
  file=$1
  expected=$2

  case "$SHA256_COMMAND" in
    sha256sum) actual=$(sha256sum "$file" | awk '{print $1}') ;;
    *) actual=$(shasum -a 256 "$file" | awk '{print $1}') ;;
  esac

  [ "$actual" = "$expected" ] || die "SHA-256 mismatch for $file (expected $expected, got $actual)."
}

print_plan() {
  mode=$1
  adapter=$2
  no_service=$3

  say "Yantraxa bridge installer ${BRIDGE_VERSION}"
  say "Plan:"
  if [ "$mode" = "uninstall" ]; then
    say "  1. Stop the login service if the installed bridge supports it."
    say "  2. Revoke this machine's local credential."
    say "  3. Uninstall yantraxa-bridge and remove ~/.yantraxa."
    say "  uv itself and other uv-managed tools will be left in place."
    return
  fi

  say "  1. Use uv ${UV_VERSION}, installing its verified release script if uv is absent."
  say "  2. Install yantraxa-bridge==${BRIDGE_VERSION} with managed Python 3.12."
  say "  3. Verify uv installed yantraxa-bridge ${BRIDGE_VERSION} and that it runs."
  if [ -n "$adapter" ]; then
    say "  4. Pair adapter ${adapter} with ${SERVER_URL}."
    if [ "$no_service" -eq 1 ]; then
      say "  5. Leave the login service off (--no-service)."
    else
      say "  5. Start the bridge automatically at login (opt out with --no-service)."
    fi
  else
    say "  Pairing will not run because no adapter was supplied."
  fi
  say "  Files are written only under ~/.local and ~/.yantraxa; administrator access is never used."
}

configure_uv_storage() {
  UV_CACHE_DIR="$HOME/.local/share/uv/cache"
  UV_PYTHON_INSTALL_DIR="$HOME/.local/share/uv/python"
  UV_PYTHON_BIN_DIR="$HOME/.local/bin"
  UV_TOOL_DIR="$HOME/.local/share/uv/tools"
  UV_TOOL_BIN_DIR="$HOME/.local/bin"
  export UV_CACHE_DIR UV_PYTHON_INSTALL_DIR UV_PYTHON_BIN_DIR UV_TOOL_DIR UV_TOOL_BIN_DIR
}

install_uv() {
  if command -v uv >/dev/null 2>&1; then
    UV_BIN=$(command -v uv)
    say "- Using existing uv: $UV_BIN"
    return
  fi

  find_sha256_command
  command -v curl >/dev/null 2>&1 || die 'curl is required to download uv.'
  command -v mktemp >/dev/null 2>&1 || die 'mktemp is required to install uv safely.'

  mkdir -p "$HOME/.local/bin" "$HOME/.local/share/uv" "$HOME/.yantraxa/tmp"
  INSTALL_TMP=$(mktemp -d "$HOME/.yantraxa/tmp/install.XXXXXX")
  installer="$INSTALL_TMP/uv-installer.sh"

  say "- Downloading uv ${UV_VERSION} from its versioned GitHub release"
  curl -fsSL "$UV_INSTALLER_URL" -o "$installer"
  verify_sha256 "$installer" "$UV_INSTALLER_SHA256"
  say "- SHA-256 verified: $UV_INSTALLER_SHA256"

  UV_NO_MODIFY_PATH=1 \
    UV_INSTALL_DIR="$HOME/.local/bin" \
    TMPDIR="$HOME/.yantraxa/tmp" \
    sh "$installer"

  UV_BIN="$HOME/.local/bin/uv"
  [ -x "$UV_BIN" ] || die "uv did not install at $UV_BIN."
}

bridge_path() {
  printf '%s\n' "$HOME/.local/bin/yantraxa-bridge"
}

# How to type the bridge in follow-up commands: its full path unless ~/.local/bin is
# already on PATH, so every printed command works when pasted as it is.
bridge_command() {
  case ":$PATH:" in
    *":$HOME/.local/bin:"*) printf '%s\n' "yantraxa-bridge" ;;
    *) bridge_path ;;
  esac
}

say_manual_start() {
  cmd=$(bridge_command)
  say "Start the bridge for this session with:"
  say "  $cmd run"
  say "Or start it automatically at login with:"
  say "  $cmd service install"
}

# Whether there is a terminal to ask on. `curl … | sh` reads the script from stdin, so
# ask on /dev/tty, but only if it really opens: without a controlling terminal it can
# pass -r and -w and still fail with "Device not configured".
tty_usable() {
  [ -r /dev/tty ] && [ -w /dev/tty ] && (: < /dev/tty > /dev/tty) 2>/dev/null
}

# The login service is the default: Enter (or no terminal to ask on) installs it.
install_service() {
  bridge=$1
  no_service=$2

  if [ "$no_service" -eq 1 ]; then
    say "- Skipping the login service (--no-service)"
    say_manual_start
    return
  fi

  if ! "$bridge" service install --help >/dev/null 2>&1; then
    say "The login service command is not available in this bridge version."
    say "Start it manually when you want the agent online:"
    say "  $(bridge_command) run"
    return
  fi

  if tty_usable; then
    printf 'Start Yantraxa Bridge automatically at login? [Y/n] ' > /dev/tty
    answer=''
    IFS= read -r answer < /dev/tty || answer=''
    case "$answer" in
      n | N | no | NO | No)
        say_manual_start
        return
        ;;
    esac
  fi

  if "$bridge" service install; then
    say "Yantraxa Bridge will start at login."
  else
    say "The login service could not be set up." >&2
    say_manual_start
  fi
}

install_bridge() {
  adapter=$1
  no_service=$2

  configure_uv_storage
  install_uv
  mkdir -p "$HOME/.local/bin" "$HOME/.local/share/uv" "$HOME/.yantraxa/tmp"

  say "- Installing yantraxa-bridge ${BRIDGE_VERSION} from PyPI"
  TMPDIR="$HOME/.yantraxa/tmp" "$UV_BIN" --no-config tool install \
    "yantraxa-bridge==${BRIDGE_VERSION}" --python 3.12

  bridge=$(bridge_path)
  [ -x "$bridge" ] || die "yantraxa-bridge was not installed at $bridge."
  version_output=$("$UV_BIN" --no-config tool list 2>/dev/null | grep '^yantraxa-bridge v' || true)
  case "$version_output" in
    "yantraxa-bridge v${BRIDGE_VERSION}" | "yantraxa-bridge v${BRIDGE_VERSION} "*) say "- Checking: $version_output" ;;
    *) die "Expected yantraxa-bridge v${BRIDGE_VERSION}, got: ${version_output:-nothing}" ;;
  esac
  "$bridge" --help >/dev/null 2>&1 || die "yantraxa-bridge ${BRIDGE_VERSION} was installed but does not run."

  if [ -z "$adapter" ]; then
    say "Installed successfully. Next, run:"
    say "  $(bridge_command) pair"
  else
    say "- Pairing ${adapter} with Yantraxa"
    "$bridge" pair --server "$SERVER_URL" --adapter "$adapter" --yes --no-service
    install_service "$bridge" "$no_service"
  fi

  case ":$PATH:" in
    *":$HOME/.local/bin:"*) ;;
    *)
      say "Add the bridge to future shells with:"
      say '  export PATH="$HOME/.local/bin:$PATH"'
      ;;
  esac
}

uninstall_bridge() {
  configure_uv_storage
  bridge=$(bridge_path)

  if [ -x "$bridge" ]; then
    if "$bridge" service uninstall --help >/dev/null 2>&1; then
      if "$bridge" service uninstall; then
        say "- Removed the login service"
      else
        say "- The login service could not be removed; continuing with local uninstall" >&2
      fi
    fi
    if "$bridge" revoke-local; then
      say "- Removed the local bridge credential"
    fi
  fi

  if command -v uv >/dev/null 2>&1; then
    UV_BIN=$(command -v uv)
  elif [ -x "$HOME/.local/bin/uv" ]; then
    UV_BIN="$HOME/.local/bin/uv"
  else
    UV_BIN=''
  fi

  if [ -n "$UV_BIN" ]; then
    if "$UV_BIN" --no-config tool uninstall yantraxa-bridge; then
      say "- Uninstalled yantraxa-bridge"
    else
      say "- yantraxa-bridge was not installed by uv"
    fi
  else
    say "- uv was not found; skipping the tool uninstall"
  fi

  if [ -d "$HOME/.yantraxa" ]; then
    rm -rf -- "$HOME/.yantraxa"
    say "- Removed $HOME/.yantraxa"
  fi
  say "Also revoke the agent in Yantraxa if it still appears there."
}

main() {
  assert_safe_home
  umask 077

  dry_run=0
  uninstall=0
  no_service=0
  adapter=''
  INSTALL_TMP=''
  trap '[ -z "$INSTALL_TMP" ] || rm -rf -- "$INSTALL_TMP"' 0 HUP INT TERM

  while [ "$#" -gt 0 ]; do
    case "$1" in
      --dry-run) dry_run=1 ;;
      --uninstall) uninstall=1 ;;
      --no-service) no_service=1 ;;
      --help | -h)
        usage
        return
        ;;
      claude-code | codex-cli | ollama)
        [ -z "$adapter" ] || die 'Only one adapter may be supplied.'
        adapter=$1
        ;;
      *)
        usage >&2
        die "Unknown argument: $1"
        ;;
    esac
    shift
  done

  [ "$uninstall" -eq 0 ] || [ -z "$adapter" ] || die 'An adapter cannot be used with --uninstall.'

  if [ "$uninstall" -eq 1 ]; then
    mode='uninstall'
  else
    mode='install'
  fi
  print_plan "$mode" "$adapter" "$no_service"

  if [ "$dry_run" -eq 1 ]; then
    say "Dry run: no files, settings, or services were changed."
    return
  fi

  if [ "$uninstall" -eq 1 ]; then
    uninstall_bridge
  else
    install_bridge "$adapter" "$no_service"
  fi
}

main "$@"
