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

fail() { printf 'install-tailnet-edge: %s\n' "$*" >&2; exit 1; }
[[ ${EUID:-$(id -u)} -eq 0 || -n ${OVERDECK_SUBROUTER_EDGE_TEST_ROOT:-} ]] || fail 'root required (invoke through deck-sudo)'

MODULE=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
SOURCE="$MODULE/lib/tailnet_edge.py"
UNIT_SOURCE="$MODULE/systemd/overdeck-subrouter-edge.service"
[[ -f "$SOURCE" && ! -L "$SOURCE" && -f "$UNIT_SOURCE" && ! -L "$UNIT_SOURCE" ]] || fail 'edge source/unit missing or symlinked'

PORT=31416
UPSTREAM_PORT=31415
ALLOWED=()
while (($#)); do
  case "$1" in
    --allow-host) [[ $# -ge 2 && -n $2 ]] || fail '--allow-host requires a value'; ALLOWED+=("$2"); shift 2 ;;
    --port) [[ $# -ge 2 && $2 =~ ^[0-9]+$ ]] || fail '--port requires an integer'; PORT=$2; shift 2 ;;
    *) fail "unknown argument: $1" ;;
  esac
done
((${#ALLOWED[@]})) || fail 'at least one --allow-host is required'
[[ $PORT -ge 1024 && $PORT -le 65535 ]] || fail 'port outside 1024..65535'
for host in "${ALLOWED[@]}"; do
  [[ $host =~ ^[A-Za-z0-9][A-Za-z0-9.-]{0,62}$ ]] || fail 'approved host name is invalid'
done

TEST_ROOT=${OVERDECK_SUBROUTER_EDGE_TEST_ROOT:-}
if [[ -n "$TEST_ROOT" ]]; then
  [[ "$TEST_ROOT" = /* && -d "$TEST_ROOT" ]] || fail 'test root must be an existing absolute directory'
  RUNTIME="$TEST_ROOT/var/lib/overdeck/subrouter-edge"
  ETC="$TEST_ROOT/etc/overdeck"
  UNIT_TARGET="$TEST_ROOT/etc/systemd/system/overdeck-subrouter-edge.service"
else
  RUNTIME=/var/lib/overdeck/subrouter-edge
  ETC=/etc/overdeck
  UNIT_TARGET=/etc/systemd/system/overdeck-subrouter-edge.service
fi

DIGEST=$(cat "$SOURCE" "$UNIT_SOURCE" | sha256sum | cut -d' ' -f1)
RELEASE="$RUNTIME/releases/$DIGEST"
mkdir -p "$RUNTIME/releases" "$ETC" "$(dirname "$UNIT_TARGET")"
chmod 0755 "$RUNTIME" "$RUNTIME/releases"
if [[ ! -d "$RELEASE" ]]; then
  tmp="$RUNTIME/releases/.tmp-$DIGEST-$$"
  rm -rf -- "$tmp"
  mkdir -m 0755 "$tmp"
  install -m 0555 "$SOURCE" "$tmp/tailnet_edge.py"
  python3 -m py_compile "$tmp/tailnet_edge.py"
  rm -rf "$tmp/__pycache__"
  mv "$tmp" "$RELEASE"
fi
ln -sfn "releases/$DIGEST" "$RUNTIME/.current-new"
mv -Tf "$RUNTIME/.current-new" "$RUNTIME/current"

CONFIG="$ETC/subrouter-edge.json"
TMP_CONFIG="$ETC/.subrouter-edge.json.$$"
python3 - "$TMP_CONFIG" "$PORT" "$UPSTREAM_PORT" "${ALLOWED[@]}" <<'PY'
import json, os, sys
path, port, upstream, *hosts = sys.argv[1:]
body = {
    "schema": "overdeck-subrouter-tailnet-edge/v1",
    "listen_port": int(port),
    "upstream_host": "127.0.0.1",
    "upstream_port": int(upstream),
    "allowed_hosts": hosts,
}
with open(path, "x", encoding="utf-8") as handle:
    os.fchmod(handle.fileno(), 0o640)
    json.dump(body, handle, sort_keys=True, separators=(",", ":"))
    handle.write("\n")
    handle.flush(); os.fsync(handle.fileno())
PY
mv -f "$TMP_CONFIG" "$CONFIG"
chmod 0640 "$CONFIG"
install -m 0644 "$UNIT_SOURCE" "$UNIT_TARGET"

if [[ -n "$TEST_ROOT" ]]; then
  printf 'Tailnet edge release: %s\nApproved hosts: %d\n' "$DIGEST" "${#ALLOWED[@]}"
  exit 0
fi

chown -R root:root "$RUNTIME"
chown root:overdeck-subrouter "$CONFIG"
systemctl daemon-reload
systemctl enable overdeck-subrouter-edge.service >/dev/null
# The edge resolves approved hostnames to tailnet IPs only at process startup.
# A config-only re-install must therefore restart an already-running service;
# enable --now alone leaves the old in-memory allowlist active.
systemctl restart overdeck-subrouter-edge.service
for _ in $(seq 1 20); do
  if systemctl is-active --quiet overdeck-subrouter-edge.service; then
    printf 'Tailnet edge release: %s\nApproved hosts: %d\n' "$DIGEST" "${#ALLOWED[@]}"
    exit 0
  fi
  sleep 0.25
done
systemctl status --no-pager overdeck-subrouter-edge.service >&2 || true
fail 'tailnet edge did not become active'
