#!/usr/bin/env bash
set -euo pipefail

# The release workflow fills these defaults in the downloadable
# install-rikaha-nodeops.sh wrapper. The source script remains safe to use
# directly with explicit arguments.
default_base_url=https://packages.rikaha.com/apt
default_key_url=https://packages.rikaha.com/apt/rikaha-nodeops-archive-keyring.gpg
default_key_sha256=fe035b822783b0bcd5fe726565bbf026dc1d34c55a6e3527436a3975167d439c
default_key_fingerprint=BE9475B715DF9FFDF67BAE966F5A644060EAE5AE

usage() {
  cat <<'EOF'
Usage: bootstrap-apt-repository.sh [OPTIONS]

Configure the signed Rikaha NodeOps APT source. Dry-run is the default.

Required options (or RIKAHA_APT_* environment variables):
  --base-url URL             APT repository root, HTTPS only.
  --key-url URL              URL of the exported archive keyring, HTTPS only.
  --key-sha256 HASH          Expected SHA-256 of the keyring file.
  --key-fingerprint HEX      Expected primary-key fingerprint.

Other options:
  --channel canary|stable    Repository suite (default: stable).
  --apply                    Write the keyring and APT source.
  --dry-run                  Show the plan without changing files (default).
  --root-dir ABSOLUTE_DIR    Test/staging root; production default is /.
  --help                     Show this help.

The command never runs apt update or installs packages. Run those explicitly
after reviewing the generated source.
EOF
}

base_url=${RIKAHA_APT_BASE_URL:-$default_base_url}
key_url=${RIKAHA_APT_KEY_URL:-$default_key_url}
key_sha256=${RIKAHA_APT_KEY_SHA256:-$default_key_sha256}
key_fingerprint=${RIKAHA_APT_KEY_FINGERPRINT:-$default_key_fingerprint}
channel='stable'
root_dir='/'
mode='dry-run'

while (($# > 0)); do
  case $1 in
    --help|-h)
      usage
      exit 0
      ;;
    --base-url)
      (($# >= 2)) || { printf '%s\n' '--base-url requires a value.' >&2; exit 2; }
      base_url=$2
      shift 2
      ;;
    --key-url)
      (($# >= 2)) || { printf '%s\n' '--key-url requires a value.' >&2; exit 2; }
      key_url=$2
      shift 2
      ;;
    --key-sha256)
      (($# >= 2)) || { printf '%s\n' '--key-sha256 requires a value.' >&2; exit 2; }
      key_sha256=$2
      shift 2
      ;;
    --key-fingerprint)
      (($# >= 2)) || { printf '%s\n' '--key-fingerprint requires a value.' >&2; exit 2; }
      key_fingerprint=$2
      shift 2
      ;;
    --channel)
      (($# >= 2)) || { printf '%s\n' '--channel requires a value.' >&2; exit 2; }
      channel=$2
      shift 2
      ;;
    --root-dir)
      (($# >= 2)) || { printf '%s\n' '--root-dir requires a value.' >&2; exit 2; }
      root_dir=$2
      shift 2
      ;;
    --apply)
      mode='apply'
      shift
      ;;
    --dry-run)
      mode='dry-run'
      shift
      ;;
    --*)
      printf 'Unknown option: %s\n' "$1" >&2
      usage >&2
      exit 2
      ;;
    *)
      printf 'Unexpected argument: %s\n' "$1" >&2
      usage >&2
      exit 2
      ;;
  esac
done

[[ -n $base_url ]] || { printf '%s\n' 'APT base URL is required.' >&2; exit 2; }
[[ -n $key_url ]] || { key_url="${base_url%/}/rikaha-nodeops-archive-keyring.gpg"; }
[[ $base_url == https://* && $base_url != *[[:space:]]* ]] || {
  printf '%s\n' 'APT base URL must use HTTPS and contain no whitespace.' >&2
  exit 2
}
[[ $key_url == https://* && $key_url != *[[:space:]]* ]] || {
  printf '%s\n' 'Key URL must use HTTPS and contain no whitespace.' >&2
  exit 2
}
[[ $channel == canary || $channel == stable ]] || {
  printf 'Unsupported channel: %s\n' "$channel" >&2
  exit 2
}
[[ $key_sha256 =~ ^[[:xdigit:]]{64}$ ]] || {
  printf '%s\n' 'Key SHA-256 must contain exactly 64 hexadecimal characters.' >&2
  exit 2
}
[[ $key_fingerprint =~ ^[[:xdigit:]]{40}$ ]] || {
  printf '%s\n' 'Key fingerprint must contain exactly 40 hexadecimal characters.' >&2
  exit 2
}
[[ $root_dir == /* ]] || {
  printf '%s\n' 'Root directory must be absolute.' >&2
  exit 2
}

key_path='/usr/share/keyrings/rikaha-nodeops-archive-keyring.gpg'
source_path='/etc/apt/sources.list.d/rikaha-nodeops.sources'
rooted_path() {
  local target_path=$1
  if [[ $root_dir == / ]]; then
    printf '%s' "$target_path"
  else
    printf '%s%s' "${root_dir%/}" "$target_path"
  fi
}

target_key_path=$(rooted_path "$key_path")
target_source_path=$(rooted_path "$source_path")
source_contents=$(cat <<EOF
# Managed by Rikaha Node Platform bootstrap. Do not edit.
Types: deb
URIs: ${base_url%/}
Suites: $channel
Components: main
Architectures: all
Signed-By: $key_path
EOF
)

printf 'Rikaha NodeOps APT bootstrap\n'
printf '  Mode: %s\n' "$mode"
printf '  Channel: %s\n' "$channel"
printf '  APT base URL: %s\n' "${base_url%/}"
printf '  Key URL: %s\n' "$key_url"
printf '  Key fingerprint: %s\n' "${key_fingerprint^^}"
printf '  Keyring: %s\n' "$target_key_path"
printf '  Source: %s\n' "$target_source_path"

if [[ $mode == dry-run ]]; then
  printf '%s\n' 'PLAN: download, hash-check, and fingerprint-check the archive keyring'
  printf '%s\n' 'PLAN: install the keyring and write the managed deb822 APT source'
  printf '%s\n' 'Dry run complete. No files changed.'
  exit 0
fi

if [[ $root_dir == / && $EUID -ne 0 ]]; then
  printf '%s\n' 'Apply mode requires root; use sudo for the explicit bootstrap apply.' >&2
  exit 1
fi
for required_command in cmp curl gpg install sha256sum awk grep; do
  command -v "$required_command" >/dev/null || {
    printf 'Required command is missing: %s\n' "$required_command" >&2
    exit 127
  }
done

temporary_dir=$(mktemp -d /tmp/rikaha-nodeops-bootstrap.XXXXXX)
cleanup() {
  rm -rf -- "$temporary_dir"
}
trap cleanup EXIT
downloaded_key="$temporary_dir/archive-keyring.gpg"
source_file="$temporary_dir/rikaha-nodeops.sources"
printf '%s\n' "$source_contents" >"$source_file"
curl --fail --silent --show-error --location --proto '=https' --tlsv1.2 \
  "$key_url" --output "$downloaded_key"
actual_key_sha256=$(sha256sum "$downloaded_key")
actual_key_sha256=${actual_key_sha256%% *}
[[ ${actual_key_sha256^^} == "${key_sha256^^}" ]] || {
  printf 'Archive key SHA-256 mismatch: expected=%s actual=%s\n' \
    "${key_sha256^^}" "${actual_key_sha256^^}" >&2
  exit 1
}
key_fingerprints=$(gpg --batch --show-keys --with-colons "$downloaded_key" |
  awk -F: '$1 == "fpr" {print toupper($10)}')
grep -Fxq "${key_fingerprint^^}" <<<"$key_fingerprints" || {
  printf 'Archive key fingerprint mismatch: expected=%s observed=%s\n' \
    "${key_fingerprint^^}" "${key_fingerprints//$'\n'/,}" >&2
  exit 1
}

backup_root=$(rooted_path '/var/lib/rikaha-nodeops/bootstrap-backups')
backup_dir="$backup_root/$(date -u +%Y%m%dT%H%M%SZ)"
changed_key=0
changed_source=0
if [[ -f $target_key_path ]]; then
  current_key_sha256=$(sha256sum "$target_key_path")
  current_key_sha256=${current_key_sha256%% *}
  [[ ${current_key_sha256^^} == "${key_sha256^^}" ]] || changed_key=1
else
  changed_key=1
fi
if [[ -f $target_source_path ]] && cmp -s <(printf '%s\n' "$source_contents") "$target_source_path"; then
  changed_source=0
else
  changed_source=1
fi

if ((changed_key == 1 || changed_source == 1)); then
  install -d -m 0755 "$backup_dir"
fi
if ((changed_key == 1)); then
  if [[ -e $target_key_path || -L $target_key_path ]]; then
    cp -a -- "$target_key_path" "$backup_dir/archive-keyring.gpg"
  fi
  install -D -m 0644 "$downloaded_key" "$target_key_path"
fi
if ((changed_source == 1)); then
  if [[ -e $target_source_path || -L $target_source_path ]]; then
    cp -a -- "$target_source_path" "$backup_dir/rikaha-nodeops.sources"
  fi
  install -D -m 0644 "$source_file" "$target_source_path"
fi

if ((changed_key == 0 && changed_source == 0)); then
  printf '%s\n' 'PASS: Rikaha NodeOps APT source already matches the requested trust configuration.'
else
  printf 'PASS: APT source configured; backup: %s\n' "$backup_dir"
fi
printf '%s\n' 'Next: sudo apt update && sudo apt install rikaha-nodeops'
