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

runtime=""
node_name=""
archive=false
observer=false
clock_provider="chrony"
start_service=false
dry_run=false

usage() {
  cat <<'EOF'
Usage:
  install-roko-service.sh --runtime native|docker --node-name NAME
                          [--archive] [--observer]
                          [--clock-provider chrony|timebeat]
                          [--start] [--dry-run]

Installs a non-authoring systemd service with loopback-only RPC, the public
ROKO bootnode, a persistent data path, and a clock-readiness gate.

Prerequisites:
  native  install-roko-native.sh and bootstrap-roko-chain-spec.sh
  docker  install-roko-docker.sh and bootstrap-roko-chain-spec.sh
  both    an installed, configured, and synchronized clock provider

--archive adds unpruned archive mode.
--observer enables ROKO's built-in non-authoring PTP² observer advertisement.
           Insert exactly one host-scoped sr25519 ptp2 key before starting.
--clock-provider timebeat expects an operator-licensed Timebeat service that
                 is already configured, synchronized, and active.
--start enables and starts the service after installation.

This script does not generate validator/session/PTP² keys, enroll a validator,
or enable block authoring.
EOF
}

while (($#)); do
  case "$1" in
    --runtime) runtime="${2:-}"; shift ;;
    --node-name) node_name="${2:-}"; shift ;;
    --archive) archive=true ;;
    --observer) observer=true ;;
    --clock-provider) clock_provider="${2:-}"; shift ;;
    --start) start_service=true ;;
    --dry-run) dry_run=true ;;
    -h|--help) usage; exit 0 ;;
    *) echo "Unknown argument: $1" >&2; usage >&2; exit 2 ;;
  esac
  shift
done

[[ "$runtime" == native || "$runtime" == docker ]] ||
  { echo "--runtime must be native or docker" >&2; exit 2; }
[[ "$clock_provider" == chrony || "$clock_provider" == timebeat ]] ||
  { echo "--clock-provider must be chrony or timebeat" >&2; exit 2; }
[[ "$node_name" =~ ^[A-Za-z0-9._-]{1,64}$ ]] ||
  { echo "--node-name must use 1-64 letters, digits, dots, underscores, or hyphens" >&2; exit 2; }

chain_path=/etc/roko/roko-testnet-v2.json
data_path=/var/lib/roko
unit_path=/etc/systemd/system/roko-node.service
bootnode=/dns4/boot.roko.network/tcp/30333/ws/p2p/12D3KooWKSBZRtSiGKo8ueJtazCHT89LaBi6ZAtzgbeznf4NtVGj
pruning_line=""
"$archive" && pruning_line=$'  --pruning archive \\\n'
observer_lines=""
"$observer" && observer_lines=$'  --timesync-time-source auto \\\n  --timesync-advertise-observer \\\n'

echo "ROKO service installation"
echo "  runtime: ${runtime}"
echo "  node name: ${node_name}"
echo "  archive: ${archive}"
echo "  observer: ${observer}"
echo "  clock provider: ${clock_provider}"
echo "  start now: ${start_service}"

if "$dry_run"; then
  exit 0
fi

[[ -f "$chain_path" ]] ||
  { echo "Missing $chain_path; run bootstrap-roko-chain-spec.sh first." >&2; exit 1; }
command -v systemctl >/dev/null ||
  { echo "systemd is required." >&2; exit 1; }
if [[ "$clock_provider" == chrony ]]; then
  command -v chronyc >/dev/null ||
    { echo "Chrony is required; install and synchronize it before installing the ROKO service." >&2; exit 1; }
  if systemctl cat chronyd.service >/dev/null 2>&1; then
    clock_unit=chronyd.service
  else
    clock_unit=chrony.service
  fi
  clock_gate="/usr/bin/chronyc waitsync 60 0.01"
else
  systemctl is-active --quiet timebeat.service ||
    { echo "Timebeat must be operator-licensed, configured, synchronized, and active." >&2; exit 1; }
  clock_unit=timebeat.service
  clock_gate="/usr/bin/systemctl is-active --quiet timebeat.service"
fi

task_tmp="$(mktemp)"
trap 'rm -f -- "$task_tmp"' EXIT

if [[ "$runtime" == native ]]; then
  [[ -x /usr/local/bin/roko-node ]] ||
    { echo "Missing /usr/local/bin/roko-node; run install-roko-native.sh first." >&2; exit 1; }
  if ! getent passwd roko >/dev/null; then
    if [[ "$(id -u)" -eq 0 ]]; then
      useradd --system --home-dir "$data_path" --create-home --shell /usr/sbin/nologin roko
    elif command -v sudo >/dev/null; then
      sudo useradd --system --home-dir "$data_path" --create-home --shell /usr/sbin/nologin roko
    else
      echo "Root access is required to create the roko service account." >&2
      exit 1
    fi
  fi
  cat >"$task_tmp" <<EOF
[Unit]
Description=ROKO full node
Wants=network-online.target
After=network-online.target $clock_unit
RequiresMountsFor=$data_path

[Service]
User=roko
Group=roko
ExecStartPre=$clock_gate
ExecStart=/usr/local/bin/roko-node \\
  --chain $chain_path \\
  --base-path $data_path \\
  --name $node_name \\
  --bootnodes $bootnode \\
  --port 30333 \\
  --rpc-port 9944 \\
${pruning_line}${observer_lines}  --rpc-methods Safe
Restart=on-failure
RestartSec=10
LimitNOFILE=65536
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ReadWritePaths=$data_path

[Install]
WantedBy=multi-user.target
EOF
  owner=roko
  group=roko
else
  command -v docker >/dev/null ||
    { echo "Docker is required." >&2; exit 1; }
  [[ -f /etc/roko/node-image.env ]] ||
    { echo "Missing /etc/roko/node-image.env; run install-roko-docker.sh first." >&2; exit 1; }
  cat >"$task_tmp" <<EOF
[Unit]
Description=ROKO full node (Docker)
Wants=network-online.target
After=network-online.target $clock_unit docker.service
Requires=docker.service
RequiresMountsFor=$data_path

[Service]
EnvironmentFile=/etc/roko/node-image.env
ExecStartPre=$clock_gate
ExecStart=/usr/bin/docker run --rm --name roko-node --network host \\
  --mount type=bind,src=$data_path,dst=/data \\
  --mount type=bind,src=$chain_path,dst=$chain_path,readonly \\
  \${ROKO_IMAGE} \\
  --database auto \\
  --chain $chain_path \\
  --base-path /data \\
  --name $node_name \\
  --bootnodes $bootnode \\
  --port 30333 \\
  --rpc-port 9944 \\
${pruning_line}${observer_lines}  --rpc-methods Safe
ExecStop=/usr/bin/docker stop --time 60 roko-node
Restart=on-failure
RestartSec=10
TimeoutStopSec=75
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
EOF
  owner=1000
  group=1000
fi

if [[ "$(id -u)" -eq 0 ]]; then
  install -d -o "$owner" -g "$group" -m 0750 "$data_path"
  install -o root -g root -m 0644 "$task_tmp" "$unit_path"
  systemctl daemon-reload
  systemctl enable roko-node
  "$start_service" && systemctl restart roko-node
elif command -v sudo >/dev/null; then
  sudo install -d -o "$owner" -g "$group" -m 0750 "$data_path"
  sudo install -o root -g root -m 0644 "$task_tmp" "$unit_path"
  sudo systemctl daemon-reload
  sudo systemctl enable roko-node
  "$start_service" && sudo systemctl restart roko-node
else
  echo "Root access is required to install the systemd service." >&2
  exit 1
fi

echo "Installed $unit_path"
if ! "$start_service"; then
  echo "Run 'sudo systemctl start roko-node' after the selected clock provider is synchronized."
fi
