#!/usr/bin/env bash

# -----------------------------------------------------------------------------
# PUBLIC LOADER TEMPLATE — publish dist/public/ from scripts/build-release.sh.
#
# Leave DEFAULT_LOGIN_SERVER empty to use Tailscale's hosted control plane.
# Every install must still supply a branch as the first positional argument or
# pass exactly one -b <branch>, -t <tag>, or -c <full-commit>; there is
# deliberately no default Git ref.
#
# The temporary installer authenticates as DEFAULT_NODE_TAG. Because that is a
# tag-owned identity, the private Git destination must also have an owned tag
# (for example, tag:fcos-git). Tailnet policy must allow the installer tag to
# reach that destination tag on TCP port 22 and use Tailscale SSH as the OS
# user in DEFAULT_REPO_URL. The destination must have Tailscale SSH enabled.
DEFAULT_REPO_URL=git@shipyard:fcos
DEFAULT_OCI_REPOSITORY=http://shipyard:5000/fcos/core
DEFAULT_PUBLIC_KEY=fleetcommand-system-1:xro+Z6r07dMzR5eoNtBDmUwxlyfhi+C/hUxiZ+kDmNU=
BOOTSTRAP_ROOTS=(/nix/store/bp3vb652rrh4jnxpnzy33pgwhv6ihr7i-bash-interactive-5.3p9 /nix/store/833invqvsk7anqnqrki5hqncrcllj825-coreutils-9.11 /nix/store/5m2ah9zf8zsp7a6y1hv2lfq6gzhv25xh-util-linux-2.42.3-bin /nix/store/2pfh66qmng1460mydmghrcfngckrgp0c-curl-8.22.0-bin /nix/store/vi98k7lyazj240xs82a8990gg5yqcq6g-jq-1.8.2-bin /nix/store/q9wb526c4vn8mz2sh24hpfxha83vqbsf-git-2.54.0 /nix/store/f82xir6jh4ad169dpcs8hf32pjzs7sgy-nix-2.34.8 /nix/store/5lxyvxz845rzklwn556f6cizv2sg0rrg-openssh-10.5p1 /nix/store/yc6dfj5hzxrzczj8pfrynkighbkpq3yh-iproute2-7.0.0 /nix/store/0vwpgw7w35dp1hjrmldv85vavvnscwgk-tailscale-1.98.10 /nix/store/9r02ykx9y35lf4gk6gc30gnag1y8ncp7-python3-3.13.15 /nix/store/rnbz3h9499a0bq33kkbars2mczqbfm4p-openssl-3.6.4-bin /nix/store/d40vpycqykpwilwrvrnq2a0l9fabgrvl-python3.13-cryptography-48.0.0 /nix/store/p70zyxpgzqq0qha0fvxprvsq57sv8s4m-python3.13-cffi-2.0.0 /nix/store/rarvdsa7cy6vix9qlxifnxva31vg9lns-python3.13-pycparser-3.00)
BOOTSTRAP_PATH=/nix/store/bp3vb652rrh4jnxpnzy33pgwhv6ihr7i-bash-interactive-5.3p9/bin:/nix/store/833invqvsk7anqnqrki5hqncrcllj825-coreutils-9.11/bin:/nix/store/5m2ah9zf8zsp7a6y1hv2lfq6gzhv25xh-util-linux-2.42.3-bin/bin:/nix/store/2pfh66qmng1460mydmghrcfngckrgp0c-curl-8.22.0-bin/bin:/nix/store/vi98k7lyazj240xs82a8990gg5yqcq6g-jq-1.8.2-bin/bin:/nix/store/q9wb526c4vn8mz2sh24hpfxha83vqbsf-git-2.54.0/bin:/nix/store/f82xir6jh4ad169dpcs8hf32pjzs7sgy-nix-2.34.8/bin:/nix/store/5lxyvxz845rzklwn556f6cizv2sg0rrg-openssh-10.5p1/bin:/nix/store/yc6dfj5hzxrzczj8pfrynkighbkpq3yh-iproute2-7.0.0/bin:/nix/store/0vwpgw7w35dp1hjrmldv85vavvnscwgk-tailscale-1.98.10/bin:/nix/store/9r02ykx9y35lf4gk6gc30gnag1y8ncp7-python3-3.13.15/bin:/nix/store/rnbz3h9499a0bq33kkbars2mczqbfm4p-openssl-3.6.4-bin/bin
BOOTSTRAP_PYTHONPATH=/nix/store/9r02ykx9y35lf4gk6gc30gnag1y8ncp7-python3-3.13.15/lib/python3.13/site-packages:/nix/store/d40vpycqykpwilwrvrnq2a0l9fabgrvl-python3.13-cryptography-48.0.0/lib/python3.13/site-packages:/nix/store/p70zyxpgzqq0qha0fvxprvsq57sv8s4m-python3.13-cffi-2.0.0/lib/python3.13/site-packages:/nix/store/rarvdsa7cy6vix9qlxifnxva31vg9lns-python3.13-pycparser-3.00/lib/python3.13/site-packages
ARTIFACT_CLIENT_ARCHIVE='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'
DEFAULT_LOGIN_SERVER=''
DEFAULT_NODE_TAG='tag:fcos'
DEFAULT_AUTH_TIMEOUT='15m'

# Install-policy defaults accept only 'true' or 'false'. Enabling
# DEFAULT_YES_DEDICATED_MACHINE authorizes unattended erasure only when the
# installer safely auto-selects exactly one installable disk. After FCOS is
# fully installed and its new boot entry is verified, it also removes the
# machine's pre-existing disk-backed UEFI boot entries.
DEFAULT_YES_DEDICATED_MACHINE='true'
DEFAULT_ALLOW_POWER_BUTTON='false'
DEFAULT_PERSISTENT_JOURNAL='false'
# END PUBLIC LOADER DEFAULTS
# -----------------------------------------------------------------------------

set -euo pipefail

REPO_URL="$DEFAULT_REPO_URL"
OCI_REPOSITORY="$DEFAULT_OCI_REPOSITORY"
PUBLIC_KEY="$DEFAULT_PUBLIC_KEY"
SOURCE_COMMIT=""
TAG_OBJECT=""
RELEASE_RECEIPT=""
INSTALLER_PACKAGE=""
TAILSCALE_PACKAGE=""
PROXY_PORT=""
LOGIN_SERVER="$DEFAULT_LOGIN_SERVER"
NODE_TAG="$DEFAULT_NODE_TAG"
AUTH_TIMEOUT="$DEFAULT_AUTH_TIMEOUT"
GIT_REF=""
GIT_REF_KIND=""
HOSTNAME_ARG=""
WORK_ROOT=""
TAILSCALE_PID=""
TAILSCALE_SOCKET=""
TAILSCALE_STATE=""
REVOKE_ON_EXIT=0
FORWARDED_BOOTSTRAP_ARGS=()
POSITIONAL_ARGS=()

INSTALLER_RAM_THRESHOLD_KIB=$((4 * 1024 * 1024))
INSTALLER_SWAP_TARGET_KIB=$((2 * 1024 * 1024))
INSTALLER_STORE_TARGET_KIB=$((2 * 1024 * 1024))
INSTALLER_STORE_MIN_FREE_KIB=$((1024 * 1024))

msg() { printf '\033[32m%s\033[0m\n' "$*"; }
die() {
  printf '\033[31m%s\033[0m\n' "$*" >&2
  exit 1
}
have() { command -v "$1" >/dev/null 2>&1; }

read_meminfo_kib() {
  local wanted="$1" key value _
  while read -r key value _; do
    if [[ "$key" == "${wanted}:" ]]; then
      printf '%s' "$value"
      return 0
    fi
  done </proc/meminfo
  return 1
}

read_filesystem_capacity_kib() {
  local path="$1" _filesystem total _used available _capacity _mounted
  {
    read -r _ || return 1
    read -r _filesystem total _used available _capacity _mounted || return 1
  } < <(df -Pk -- "$path" 2>/dev/null)
  [[ "$total" =~ ^[0-9]+$ && "$available" =~ ^[0-9]+$ ]] || return 1
  printf '%s %s' "$total" "$available"
}

discover_writable_store_backing() {
  local store_path="$1" store_fstype options option upperdir
  local backing_mount backing_fstype
  local _df_filesystem df_fstype _df_total _df_used _df_available _df_capacity df_mount
  local -a store_options=()

  if ! read -r store_fstype \
    < <(findmnt --kernel -rn -o FSTYPE --target "$store_path" 2>/dev/null) ||
    [[ -z "$store_fstype" ]]; then
    {
      read -r _ || return 1
      read -r _df_filesystem df_fstype _df_total _df_used \
        _df_available _df_capacity df_mount || return 1
    } < <(df -PT -- "$store_path" 2>/dev/null)
    [[ -n "$df_fstype" && -n "$df_mount" && "$df_fstype" != overlay ]] ||
      return 1
    printf '%s\t%s\t%s' "$df_mount" "$df_fstype" "$store_path"
    return 0
  fi

  if [[ "$store_fstype" == overlay ]]; then
    read -r options \
      < <(findmnt --kernel -rn -o OPTIONS --target "$store_path" 2>/dev/null) ||
      return 1
    IFS=',' read -r -a store_options <<<"$options"
    upperdir=""
    for option in "${store_options[@]}"; do
      if [[ "$option" == upperdir=* ]]; then
        upperdir="${option#upperdir=}"
        break
      fi
    done
    [[ -n "$upperdir" ]] || return 1
    if [[ ! -e "$upperdir" && "$store_path" == /nix/store &&
      -d /nix/.rw-store ]]; then
      case "$upperdir" in
        /mnt-root/nix/.rw-store/*)
          upperdir="/nix/.rw-store/${upperdir#/mnt-root/nix/.rw-store/}"
          ;;
        /sysroot/nix/.rw-store/*)
          upperdir="/nix/.rw-store/${upperdir#/sysroot/nix/.rw-store/}"
          ;;
      esac
    fi
    [[ -e "$upperdir" ]] || return 1
  else
    upperdir="$store_path"
  fi

  read -r backing_mount backing_fstype \
    < <(findmnt --kernel -rn -o TARGET,FSTYPE --target "$upperdir" 2>/dev/null) ||
    return 1
  [[ -n "$backing_mount" && -n "$backing_fstype" ]] || return 1
  printf '%s\t%s\t%s' "$backing_mount" "$backing_fstype" "$upperdir"
}

ensure_installer_swap_capacity() {
  local mem_total_kib swap_total_kib swap_needed_kib swap_needed_bytes zram_device
  local tool
  local swap_minimum_kib=$((INSTALLER_SWAP_TARGET_KIB - 1024))

  mem_total_kib="$(read_meminfo_kib MemTotal)"
  swap_total_kib="$(read_meminfo_kib SwapTotal)"
  [[ "$mem_total_kib" =~ ^[0-9]+$ && "$swap_total_kib" =~ ^[0-9]+$ ]] ||
    die "Unable to read installer memory capacity from /proc/meminfo."

  if ((mem_total_kib >= INSTALLER_RAM_THRESHOLD_KIB || \
    swap_total_kib >= swap_minimum_kib)); then
    return
  fi

  swap_needed_kib=$((INSTALLER_SWAP_TARGET_KIB - swap_total_kib))
  swap_needed_bytes=$((swap_needed_kib * 1024))
  for tool in modprobe mkswap swapon zramctl; do
    have "$tool" ||
      die "Missing required low-memory NixOS installer command: $tool; no target-disk changes were made."
  done
  msg "Low-memory installer detected; enabling $((swap_needed_kib / 1024)) MiB of temporary zram swap."
  modprobe zram num_devices=1 ||
    die "Unable to load zram. A fresh installation below 4 GiB RAM requires 2 GiB of active swap; no target-disk changes were made."
  zram_device="$(zramctl --find --size "$swap_needed_bytes")" ||
    die "Unable to allocate temporary zram. A fresh installation below 4 GiB RAM requires 2 GiB of active swap; no target-disk changes were made."
  [[ -n "$zram_device" ]] || die "zramctl did not return a temporary swap device; no target-disk changes were made."
  mkswap "$zram_device" >/dev/null ||
    die "Unable to format temporary swap device $zram_device; no target-disk changes were made."
  swapon --priority 100 "$zram_device" ||
    die "Unable to activate temporary swap on $zram_device; no target-disk changes were made."

  swap_total_kib="$(read_meminfo_kib SwapTotal)"
  [[ "$swap_total_kib" =~ ^[0-9]+$ && "$swap_total_kib" -ge "$swap_minimum_kib" ]] ||
    die "Temporary zram activation did not provide the required 2 GiB of installer swap; no target-disk changes were made."
  msg "Temporary installer swap active on $zram_device."
}

ensure_installer_writable_store_capacity() {
  local store_path="${1:-/nix/store}"
  local target_kib="${2:-$INSTALLER_STORE_TARGET_KIB}"
  local min_free_kib="${3:-$INSTALLER_STORE_MIN_FREE_KIB}"
  local backing backing_mount backing_fstype backing_path total_kib available_kib

  backing="$(discover_writable_store_backing "$store_path")" ||
    die "Unable to identify the live installer's writable Nix-store backing filesystem; no target-disk changes were made."
  IFS=$'\t' read -r backing_mount backing_fstype backing_path <<<"$backing"
  read -r total_kib available_kib \
    <<<"$(read_filesystem_capacity_kib "$backing_path")" ||
    die "Unable to measure writable Nix-store capacity at $backing_mount; no target-disk changes were made."

  if ((total_kib < target_kib)) && [[ "$backing_fstype" == tmpfs ]]; then
    msg "Expanding the live installer's volatile writable Nix store to $((target_kib / 1024)) MiB..."
    mount -o "remount,size=${target_kib}K" "$backing_mount" ||
      die "Unable to expand writable Nix-store tmpfs $backing_mount to $((target_kib / 1024)) MiB; no target-disk changes were made."
    read -r total_kib available_kib \
      <<<"$(read_filesystem_capacity_kib "$backing_path")" ||
      die "Unable to verify writable Nix-store capacity after expanding $backing_mount; no target-disk changes were made."
  fi

  if ((total_kib < target_kib || available_kib < min_free_kib)); then
    die "The live installer's writable Nix store at $backing_mount ($backing_fstype) has $((total_kib / 1024)) MiB total and $((available_kib / 1024)) MiB free; at least $((target_kib / 1024)) MiB total and $((min_free_kib / 1024)) MiB free are required. Reboot the installer to clear cached downloads or use the supported NixOS minimal ISO; no target-disk changes were made."
  fi

  msg "Installer writable Nix store ready: $((total_kib / 1024)) MiB total, $((available_kib / 1024)) MiB free on $backing_mount."
}

prepare_installer_runtime_capacity() {
  ensure_installer_swap_capacity
  ensure_installer_writable_store_capacity
}

normalize_nixos_path() {
  local bin_dir
  # Interactive installer shells normally include these paths. Transient
  # services and sudo policies may not, even though the commands are present
  # in the live NixOS closure.
  for bin_dir in /run/current-system/sw/bin /nix/var/nix/profiles/default/bin; do
    [[ ! -d "$bin_dir" ]] || PATH="$bin_dir:$PATH"
  done
  export PATH
}

usage() {
  cat >&2 <<'EOF'
Usage: install.sh <branch> [loader options] [install options] [hostname]
       install.sh (-b <branch> | -t <tag> | -c <full-commit>) [loader options] [install options] [hostname]

Required (choose exactly one):
  <branch>                Install this branch when no ref flag is supplied.
  -b <branch>             Install an explicitly selected branch.
  -t <tag>                Install an explicitly selected tag.
  -c <full-commit>        Install and pin a full lowercase Git commit hash.

Loader options:
  --repo-url <url>        Private SSH Git URL (default is embedded at publish time).
  --login-server <url>    Headscale or other compatible control-server URL.
  --tailscale-saas        Use Tailscale's hosted control plane.
  --node-tag <tag:name>   Tag requested for the new FCOS identity.
  --auth-timeout <time>   Browser-approval window, from 1s through 1h.

Install options passed to the private bootstrap:
  --yes-dedicated-machine    Authorize unattended dedicated-machine takeover
                             only when exactly one disk is safely selected.
  --require-disk-confirmation
                             Require manual disk and UEFI-cleanup decisions.
  --admin-password-file <path>
  --admin-password-hash <hash>
  --prompt-admin-password
  --allow-power-button
  --ignore-power-button
  --persistent-journal
  --volatile-journal
  --pin-tag                 Keep the selected initial tag pinned.
  --fcav-setup-url <https-url>

The dedicated-machine option erases the selected disk and, only after FCOS is
fully installed and its new boot entry is verified, removes pre-existing
disk-backed UEFI boot entries. Firmware and network-boot entries are preserved.
The positive install flags enable their matching published defaults for one
run. The paired inverse flags disable an enabled published default for one run.

The loader never supplies a default branch or tag. It creates a temporary,
root-only Tailscale identity, resolves the selected private ref via
Tailscale SSH, verifies its signed OCI release, and runs only its prebuilt installer.

The Git destination must be tag-owned, have Tailscale SSH enabled, and permit
the requested node tag on TCP port 22 and through a noninteractive SSH rule.
EOF
}

validate_git_ref() {
  [[ "$1" =~ ^[A-Za-z0-9][A-Za-z0-9._/@+-]{0,127}$ ]]
}

duration_seconds() {
  local value="$1" number multiplier
  [[ "$value" =~ ^([1-9][0-9]*)([smh])$ ]] || return 1
  number="${BASH_REMATCH[1]}"
  case "${BASH_REMATCH[2]}" in
    s) multiplier=1 ;;
    m) multiplier=60 ;;
    h) multiplier=3600 ;;
  esac
  ((number * multiplier <= 3600)) || return 1
  printf '%s' "$((number * multiplier))"
}

validate_node_tag() {
  [[ "$1" =~ ^tag:[A-Za-z0-9][A-Za-z0-9_.-]{0,62}$ ]]
}

validate_boolean() {
  [[ "$1" == true || "$1" == false ]]
}

validate_login_server() {
  local url="$1"
  [[ -z "$url" ]] && return 0
  [[ "$url" != *$'\n'* && "$url" != *$'\r'* && "$url" != *[[:space:]]* ]] || return 1
  [[ "$url" =~ ^https?://[A-Za-z0-9][A-Za-z0-9.-]*(:[0-9]{1,5})?/?$ ]]
}

git_remote_host() {
  local url="$1" authority host
  if [[ "$url" =~ ^[A-Za-z_][A-Za-z0-9._-]*@([A-Za-z0-9][A-Za-z0-9.-]*):[^[:space:]]+$ ]]; then
    printf '%s' "${BASH_REMATCH[1]}"
    return 0
  fi
  if [[ "$url" == ssh://* ]]; then
    authority="${url#ssh://}"
    authority="${authority%%/*}"
    [[ "$authority" == *@* ]] || return 1
    host="${authority#*@}"
    host="${host%%:*}"
    [[ "$host" =~ ^[A-Za-z0-9][A-Za-z0-9.-]*$ ]] || return 1
    printf '%s' "$host"
    return 0
  fi
  return 1
}

validate_repo_url() {
  local url="$1" authority userinfo
  [[ "$url" != *$'\n'* && "$url" != *$'\r'* && "$url" != *[[:space:]]* ]] || return 1
  if [[ "$url" == ssh://* ]]; then
    authority="${url#ssh://}"
    authority="${authority%%/*}"
    userinfo="${authority%@*}"
    [[ "$authority" == *@* && "$userinfo" != *:* && "$url" == ssh://*/* ]] || return 1
  elif [[ ! "$url" =~ ^[A-Za-z_][A-Za-z0-9._-]*@[A-Za-z0-9][A-Za-z0-9.-]*:[^[:space:]]+$ ]]; then
    return 1
  fi
  git_remote_host "$url" >/dev/null
}

parse_args() {
  local yes_dedicated_machine="$DEFAULT_YES_DEDICATED_MACHINE"
  local allow_power_button="$DEFAULT_ALLOW_POWER_BUTTON"
  local persistent_journal="$DEFAULT_PERSISTENT_JOURNAL"

  validate_boolean "$yes_dedicated_machine" ||
    die "DEFAULT_YES_DEDICATED_MACHINE must be 'true' or 'false'."
  validate_boolean "$allow_power_button" ||
    die "DEFAULT_ALLOW_POWER_BUTTON must be 'true' or 'false'."
  validate_boolean "$persistent_journal" ||
    die "DEFAULT_PERSISTENT_JOURNAL must be 'true' or 'false'."

  POSITIONAL_ARGS=()
  FORWARDED_BOOTSTRAP_ARGS=()
  while [[ $# -gt 0 ]]; do
    case "$1" in
      --install)
        shift
        ;;
      --upgrade)
        die "The public loader is only for fresh installs."
        ;;
      -b | -t | -c)
        [[ -z "$GIT_REF" ]] || die "Use only one Git ref flag: -b <branch>, -t <tag>, or -c <full-commit>."
        [[ -n "${2:-}" && "${2:-}" != -* ]] || die "Missing or invalid argument for $1"
        GIT_REF="$2"
        case "$1" in
          -b) GIT_REF_KIND="branch" ;;
          -t) GIT_REF_KIND="tag" ;;
          -c) GIT_REF_KIND="commit" ;;
        esac
        shift 2
        ;;
      --repo-url)
        [[ -n "${2:-}" && "${2:-}" != -* ]] || die "Missing or invalid argument for $1"
        REPO_URL="$2"
        shift 2
        ;;
      --login-server)
        [[ -n "${2:-}" && "${2:-}" != -* ]] || die "Missing or invalid argument for $1"
        LOGIN_SERVER="$2"
        shift 2
        ;;
      --tailscale-saas)
        LOGIN_SERVER=""
        shift
        ;;
      --node-tag)
        [[ -n "${2:-}" && "${2:-}" != -* ]] || die "Missing or invalid argument for $1"
        NODE_TAG="$2"
        shift 2
        ;;
      --auth-timeout)
        [[ -n "${2:-}" && "${2:-}" != -* ]] || die "Missing or invalid argument for $1"
        AUTH_TIMEOUT="$2"
        shift 2
        ;;
      --yes-dedicated-machine)
        yes_dedicated_machine=true
        shift
        ;;
      --require-disk-confirmation)
        yes_dedicated_machine=false
        shift
        ;;
      --allow-power-button)
        allow_power_button=true
        shift
        ;;
      --ignore-power-button)
        allow_power_button=false
        shift
        ;;
      --persistent-journal)
        persistent_journal=true
        shift
        ;;
      --volatile-journal)
        persistent_journal=false
        shift
        ;;
      --prompt-admin-password | --pin-tag)
        FORWARDED_BOOTSTRAP_ARGS+=("$1")
        shift
        ;;
      --admin-password-file | --admin-password-hash | --fcav-setup-url)
        [[ -n "${2:-}" ]] || die "Missing argument for $1"
        FORWARDED_BOOTSTRAP_ARGS+=("$1" "$2")
        shift 2
        ;;
      -h | --help)
        usage
        exit 0
        ;;
      --)
        shift
        POSITIONAL_ARGS+=("$@")
        break
        ;;
      -*)
        die "Unknown flag: $1"
        ;;
      *)
        POSITIONAL_ARGS+=("$1")
        shift
        ;;
    esac
  done

  if [[ -z "$GIT_REF" && ${#POSITIONAL_ARGS[@]} -gt 0 ]]; then
    GIT_REF="${POSITIONAL_ARGS[0]}"
    GIT_REF_KIND="branch"
    POSITIONAL_ARGS=("${POSITIONAL_ARGS[@]:1}")
  fi

  [[ -n "$GIT_REF" ]] ||
    die "Fresh install requires a branch argument, -b <branch>, -t <tag>, or -c <full-commit>; no default ref exists."
  validate_git_ref "$GIT_REF" || die "Invalid Git ${GIT_REF_KIND}: $GIT_REF"
  if [[ "$GIT_REF_KIND" == commit && ! "$GIT_REF" =~ ^[0-9a-f]{40}$ ]]; then
    die "Commit selection requires a full lowercase 40-character Git hash."
  fi
  validate_repo_url "$REPO_URL" || die "Repository URL must be a credential-free SSH URL such as git@shipyard:fcos."
  validate_login_server "$LOGIN_SERVER" || die "Control-server URL must be an HTTP(S) origin without credentials, query, fragment, or path."
  validate_node_tag "$NODE_TAG" || die "Invalid node tag: $NODE_TAG"
  duration_seconds "$AUTH_TIMEOUT" >/dev/null || die "Authentication timeout must be from 1s through 1h (for example, 15m)."
  [[ ${#POSITIONAL_ARGS[@]} -le 1 ]] || die "Unexpected extra argument: ${POSITIONAL_ARGS[1]}"
  HOSTNAME_ARG="${POSITIONAL_ARGS[0]:-}"

  [[ "$yes_dedicated_machine" == false ]] || FORWARDED_BOOTSTRAP_ARGS+=(--yes-dedicated-machine)
  [[ "$allow_power_button" == false ]] || FORWARDED_BOOTSTRAP_ARGS+=(--allow-power-button)
  [[ "$persistent_journal" == false ]] || FORWARDED_BOOTSTRAP_ARGS+=(--persistent-journal)
}

check_root_and_runtime() {
  local tool
  [[ -n "${BASH_VERSION:-}" ]] || die "Run this loader with bash, not sh."
  [[ "$EUID" -eq 0 ]] || die "Run this loader as root (sudo)."
  [[ "$(uname -m)" == x86_64 && -d /sys/firmware/efi ]] || die "FleetCommandOS requires an x86_64 machine booted in UEFI mode."
  for tool in df findmnt mount; do
    have "$tool" || die "Missing required NixOS installer command: $tool"
  done
  [[ "$(findmnt -n -o FSTYPE /run 2>/dev/null || true)" == tmpfs ]] ||
    die "/run must be a tmpfs so the temporary Tailnet identity never lands on installer media."
}

create_work_root() {
  local attempt candidate
  umask 077
  if have mktemp; then
    WORK_ROOT="$(mktemp -d /run/fleetcommand-private-install.XXXXXX)"
  else
    # Some minimal NixOS installer environments omit mktemp from the initial
    # system PATH. mkdir is atomic, so a PID/random candidate still gives us a
    # safe root-private directory from which to install the remaining tools.
    for attempt in {1..100}; do
      candidate="/run/fleetcommand-private-install.${BASHPID}.${RANDOM}.${attempt}"
      if mkdir -m 0700 -- "$candidate" 2>/dev/null; then
        WORK_ROOT="$candidate"
        break
      fi
    done
    [[ -n "$WORK_ROOT" ]] || die "Unable to create a private temporary directory under /run."
  fi
  chmod 0700 "$WORK_ROOT"
  mkdir -m 0700 "$WORK_ROOT/home" "$WORK_ROOT/config"
  export HOME="$WORK_ROOT/home"
  export XDG_CONFIG_HOME="$WORK_ROOT/config"
  TAILSCALE_SOCKET="$WORK_ROOT/tailscaled.sock"
  TAILSCALE_STATE="$WORK_ROOT/tailscaled.state"
}

ensure_tools() {
  [[ "$DEFAULT_OCI_REPOSITORY" != @FCOS_* && "$ARTIFACT_CLIENT_ARCHIVE" != @FCOS_* ]] || die "This is the loader template; publish the generated dist/public/install.sh."
  have nix-store || die "The NixOS installer must provide nix-store."
  mkdir -m 0700 "$WORK_ROOT/tool-roots"
  msg "Downloading verified bootstrap tools from the official NixOS cache..."
  nix-store --realise --add-root "$WORK_ROOT/tool-roots/tool" --indirect \
    --option substituters https://cache.nixos.org \
    --option trusted-public-keys 'cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=' \
    --option require-sigs true --option max-jobs 0 --option fallback false \
    "${BOOTSTRAP_ROOTS[@]}" >/dev/null || die "Official bootstrap tools are unavailable. No source compilation was attempted."
  export PATH="$BOOTSTRAP_PATH:$PATH"
  mkdir -m 0700 "$WORK_ROOT/client"
  printf '%s' "$ARTIFACT_CLIENT_ARCHIVE" | python3 -c '
import base64, io, pathlib, sys, zipfile
with zipfile.ZipFile(io.BytesIO(base64.b64decode(sys.stdin.buffer.read(), validate=True))) as archive:
    for member in archive.namelist():
        path = pathlib.PurePosixPath(member)
        if path.is_absolute() or ".." in path.parts or not (
            member.startswith("artifacts/") or member == "signatures.py"
        ):
            raise SystemExit("Unsafe embedded artifact client")
    archive.extractall(sys.argv[1])
' "$WORK_ROOT/client"
  export PYTHONPATH="$WORK_ROOT/client:$BOOTSTRAP_PYTHONPATH"
  export PYTHONDONTWRITEBYTECODE=1
  local tool
  for tool in git jq ssh tailscale tailscaled python3 openssl; do
    have "$tool" || die "Official bootstrap tools did not provide $tool."
  done
}

resolve_source() {
  local repo_host records object_hash reference
  if [[ "$GIT_REF_KIND" == commit ]]; then
    SOURCE_COMMIT="$GIT_REF"
    return
  fi
  repo_host="$(git_remote_host "$REPO_URL")"
  ts ping --timeout=10s --c=3 --until-direct=false "$repo_host" >/dev/null || die "The Git peer is not reachable over the Tailnet."
  export GIT_TERMINAL_PROMPT=0
  export GIT_SSH_COMMAND="tailscale --socket=$TAILSCALE_SOCKET ssh"
  export GIT_SSH_VARIANT=simple
  if [[ "$GIT_REF_KIND" == branch ]]; then
    records="$(git ls-remote --exit-code --heads "$REPO_URL" "refs/heads/$GIT_REF")" || die "Cannot resolve the selected branch over Tailscale SSH. Check TCP port 22 and Tailscale SSH authorization."
    while read -r object_hash reference; do
      if [[ "$reference" == "refs/heads/$GIT_REF" ]]; then
        [[ -z "$SOURCE_COMMIT" ]] || die "The selected branch has an ambiguous response."
        SOURCE_COMMIT="$object_hash"
      fi
    done <<<"$records"
  else
    records="$(git ls-remote --exit-code --tags "$REPO_URL" "refs/tags/$GIT_REF" "refs/tags/$GIT_REF^{}")" || die "Cannot resolve the selected tag over Tailscale SSH. Check TCP port 22 and Tailscale SSH authorization."
    while read -r object_hash reference; do
      if [[ "$reference" == "refs/tags/$GIT_REF" ]]; then
        [[ -z "$TAG_OBJECT" ]] || die "The selected tag has an ambiguous response."
        TAG_OBJECT="$object_hash"
      elif [[ "$reference" == "refs/tags/$GIT_REF^{}" ]]; then
        [[ -z "$SOURCE_COMMIT" ]] || die "The selected tag has an ambiguous peeled commit."
        SOURCE_COMMIT="$object_hash"
      fi
    done <<<"$records"
    [[ "$TAG_OBJECT" =~ ^[0-9a-f]{40}$ ]] || die "The selected tag has no valid Git identity."
    SOURCE_COMMIT="${SOURCE_COMMIT:-$TAG_OBJECT}"
  fi
  [[ "$SOURCE_COMMIT" =~ ^[0-9a-f]{40}$ ]] || die "The selected source did not resolve to one full commit."
}

prepare_signed_installer() {
  local imported
  RELEASE_RECEIPT="$WORK_ROOT/release.json"
  msg "Verifying the published system for commit $SOURCE_COMMIT..."
  python3 -m artifacts.cli resolve --repository "$OCI_REPOSITORY" \
    --commit "$SOURCE_COMMIT" --source-repository "$REPO_URL" --public-key "$PUBLIC_KEY" \
    --output "$RELEASE_RECEIPT" --proxy "http://127.0.0.1:$PROXY_PORT" \
    --tailscale-socket "$TAILSCALE_SOCKET" >/dev/null || die "No valid signed system is published for this exact commit. No disk changes were made."
  chmod 0600 "$RELEASE_RECEIPT"
  imported="$(python3 -m artifacts.cli import --release-file "$RELEASE_RECEIPT" \
    --public-key "$PUBLIC_KEY" --role tailscale --role installer --store local \
    --scratch-dir "$WORK_ROOT/import" --roots-dir "$WORK_ROOT/release-roots" \
    --reserve-bytes 134217728 --proxy "http://127.0.0.1:$PROXY_PORT" \
    --tailscale-socket "$TAILSCALE_SOCKET")" || die "Signed installer tools are unavailable. No disk changes or source builds were attempted."
  INSTALLER_PACKAGE="$(jq -er .roots.installer <<<"$imported")"
  TAILSCALE_PACKAGE="$(jq -er .roots.tailscale <<<"$imported")"
  [[ -x "$INSTALLER_PACKAGE/bin/fleetcommand-install" && -x "$TAILSCALE_PACKAGE/bin/tailscaled" ]] || die "Published installer tools are incomplete."
}

write_handoff_and_exec() {
  local manifest stable_id ipv4
  manifest="$WORK_ROOT/install-handoff.json"
  stable_id="$(ts status --json | jq -er '.Self.ID')"
  ipv4="$(ts status --json | jq -er '.Self.TailscaleIPs[] | select(test("^[0-9]+\\."))' | head -n 1)"
  [[ -n "$ipv4" ]] || die "The authenticated identity has no Tailscale IPv4 address."
  stop_tailscaled
  [[ -s "$TAILSCALE_STATE" ]] || die "The authenticated Tailscale state is missing."
  chmod 0600 "$TAILSCALE_STATE"
  jq -n --arg repoUrl "$REPO_URL" --arg refKind "$GIT_REF_KIND" --arg ref "$GIT_REF" \
    --arg commit "$SOURCE_COMMIT" --arg receipt "$RELEASE_RECEIPT" --arg repository "$OCI_REPOSITORY" \
    --arg publicKey "$PUBLIC_KEY" --arg tagObject "$TAG_OBJECT" --arg stateFile "$TAILSCALE_STATE" \
    --arg stableId "$stable_id" --arg ipv4 "$ipv4" --arg loginServer "$LOGIN_SERVER" \
    --arg nodeTag "$NODE_TAG" --argjson proxyPort "$PROXY_PORT" \
    '{schemaVersion:1,repoUrl:$repoUrl,refKind:$refKind,ref:$ref,commit:$commit,receipt:$receipt,
      distribution:{repository:$repository,publicKeys:[$publicKey]},
      tagObject:(if $tagObject=="" then null else $tagObject end),
      tailscale:{stateFile:$stateFile,stableId:$stableId,ipv4:$ipv4,proxyPort:$proxyPort,
        loginServer:(if $loginServer=="" then null else $loginServer end),nodeTag:$nodeTag}}' >"$manifest"
  chmod 0600 "$manifest"
  local arguments=(--install --install-handoff "$manifest" --repo-url "$REPO_URL")
  case "$GIT_REF_KIND" in
    branch) arguments+=(-b "$GIT_REF") ;;
    tag) arguments+=(-t "$GIT_REF") ;;
    commit) arguments+=(-c "$GIT_REF") ;;
  esac
  arguments+=("${FORWARDED_BOOTSTRAP_ARGS[@]}")
  [[ -z "$HOSTNAME_ARG" ]] || arguments+=("$HOSTNAME_ARG")
  REVOKE_ON_EXIT=0
  trap - EXIT INT TERM
  msg "Running only the verified, prebuilt installer for commit $SOURCE_COMMIT."
  exec "$INSTALLER_PACKAGE/bin/fleetcommand-install" "${arguments[@]}"
}

ts() {
  tailscale --socket="$TAILSCALE_SOCKET" "$@"
}

stop_tailscaled() {
  if [[ -n "$TAILSCALE_PID" ]] && kill -0 "$TAILSCALE_PID" 2>/dev/null; then
    kill "$TAILSCALE_PID" 2>/dev/null || true
    wait "$TAILSCALE_PID" 2>/dev/null || true
  fi
  TAILSCALE_PID=""
}

cleanup() {
  local rc=$?
  set +e
  if [[ "$REVOKE_ON_EXIT" -eq 1 && -S "$TAILSCALE_SOCKET" ]]; then
    timeout 10s tailscale --socket="$TAILSCALE_SOCKET" logout >/dev/null 2>&1 || true
  fi
  stop_tailscaled
  if [[ -n "$WORK_ROOT" && "$WORK_ROOT" == /run/fleetcommand-private-install.* && -d "$WORK_ROOT" ]]; then
    rm -rf -- "$WORK_ROOT"
  fi
  exit "$rc"
}

verify_enrolled_tag() {
  local deadline=$((SECONDS + 30)) status_json
  msg "Waiting for the control server to confirm '${NODE_TAG}'..."
  while ((SECONDS < deadline)); do
    if status_json="$(timeout 3s tailscale --socket="$TAILSCALE_SOCKET" status --json)" &&
      jq -e --arg tag "$NODE_TAG" '
        .BackendState == "Running" and
        (.Self.ID | type == "string" and length > 0) and
        ((.Self.Tags // []) | map(ascii_downcase) | index($tag | ascii_downcase) != null)
      ' <<<"$status_json" >/dev/null 2>&1; then
      msg "Control server confirmed '${NODE_TAG}'."
      if [[ -z "$LOGIN_SERVER" ]]; then
        msg "Tailscale disables device node-key expiry by default for new tagged logins. Verify Key Expiry in Tailscale Machines; existing settings may differ."
      else
        msg "Device node-key expiry is controlled by your control server. Verify its expiry policy for this appliance."
      fi
      return 0
    fi
    sleep 1
  done
  die "The control server did not confirm '${NODE_TAG}' within 30 seconds. Check that the tag exists and the authenticating account can assign it, then retry. Installation has not started."
}

start_tailscaled() {
  local loader_hostname
  PROXY_PORT="$(python3 -c 'import socket; listener=socket.socket(); listener.bind(("127.0.0.1",0)); print(listener.getsockname()[1])')"
  loader_hostname="${HOSTNAME_ARG:-fcos-installer}"
  msg "Starting an isolated Tailscale client in volatile memory..."
  tailscaled \
    --state="$TAILSCALE_STATE" \
    --statedir="$WORK_ROOT/tailscale" \
    --socket="$TAILSCALE_SOCKET" \
    --tun=userspace-networking \
    --outbound-http-proxy-listen="127.0.0.1:$PROXY_PORT" \
    --port=0 \
    --encrypt-state=false \
    --no-logs-no-support \
    >"$WORK_ROOT/tailscaled.log" 2>&1 &
  TAILSCALE_PID=$!

  for _ in $(seq 1 100); do
    [[ -S "$TAILSCALE_SOCKET" ]] && break
    kill -0 "$TAILSCALE_PID" 2>/dev/null || {
      tail -n 20 "$WORK_ROOT/tailscaled.log" >&2 || true
      die "The temporary Tailscale daemon exited before becoming ready."
    }
    sleep 0.1
  done
  [[ -S "$TAILSCALE_SOCKET" ]] || die "The temporary Tailscale daemon did not become ready."

  local up_args=(up --reset --hostname="$loader_hostname" --advertise-tags="$NODE_TAG"
    --accept-dns=false --accept-routes=false --ssh=false --qr --timeout="$AUTH_TIMEOUT")
  [[ -z "$LOGIN_SERVER" ]] || up_args+=(--login-server="$LOGIN_SERVER")

  msg "Approve the new '${NODE_TAG}' device in the browser or with the QR code below."
  if ! timeout --foreground "$AUTH_TIMEOUT" \
    tailscale --socket="$TAILSCALE_SOCKET" "${up_args[@]}"; then
    die "Tailscale authentication was not completed within $AUTH_TIMEOUT."
  fi
  REVOKE_ON_EXIT=1
  verify_enrolled_tag
}

main() {
  parse_args "$@"
  normalize_nixos_path
  check_root_and_runtime
  prepare_installer_runtime_capacity
  create_work_root
  trap cleanup EXIT
  trap 'exit 130' INT TERM
  ensure_tools
  start_tailscaled
  resolve_source
  prepare_signed_installer
  write_handoff_and_exec
}

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