#!/usr/bin/env bash
#
# Install and register Gitea Actions act_runner on Ubuntu 20.04+ (x86_64 / arm64).
# See: https://docs.gitea.com/usage/actions/act-runner/
#
# Prereq: Gitea with [actions] enabled; registration token from
#   Site: Admin → Actions → Runners (or org/repo → Settings → Actions → Runners)
#
# Non-interactive (typical for automation):
#   GITEA_INSTANCE_URL=https://gitea.example.com/ GITEA_RUNNER_REGISTRATION_TOKEN=xxxxx \
#   sudo -E bash scripts/setup-gitea-act-runner-ubuntu.sh
#
# Interactive registration (omit env vars; you will be prompted if register step runs as act_runner):
#   sudo bash scripts/setup-gitea-act-runner-ubuntu.sh
#
# Optional:
#   ACT_RUNNER_VERSION=0.2.13  # default: latest release from gitea.com API
#   GITEA_RUNNER_NAME=my-runner
#   GITEA_RUNNER_LABELS='ubuntu-22.04:docker://docker.gitea.com/runner-images:ubuntu-22.04'
#   --skip-docker              # do not install Docker; use only if you use :host labels
#   --no-systemd               # install binary + config only, no service
#   --skip-apt                 # skip apt update/install (you installed deps already)
#
set -euo pipefail

ACT_RUNNER_USER="act_runner"
ACT_RUNNER_HOME="/var/lib/${ACT_RUNNER_USER}"
ACT_RUNNER_CONFIG="/etc/act_runner/config.yaml"
ACT_RUNNER_BIN="/usr/local/bin/act_runner"

INSTALL_DOCKER=1
INSTALL_SYSTEMD=1
SKIP_APT=0

GITEA_INSTANCE_URL="${GITEA_INSTANCE_URL:-}"
GITEA_RUNNER_REGISTRATION_TOKEN="${GITEA_RUNNER_REGISTRATION_TOKEN:-}"
GITEA_RUNNER_NAME="${GITEA_RUNNER_NAME:-$(hostname 2>/dev/null || echo act-runner)}"
# Default labels match act_runner register prompts (Docker-based runners).
GITEA_RUNNER_LABELS="${GITEA_RUNNER_LABELS:-}"
ACT_RUNNER_VERSION="${ACT_RUNNER_VERSION:-}"

for arg in "$@"; do
  case "$arg" in
    --skip-docker) INSTALL_DOCKER=0 ;;
    --no-systemd) INSTALL_SYSTEMD=0 ;;
    --skip-apt) SKIP_APT=1 ;;
    -h|--help)
      sed -n '1,30p' "$0" | tail -n +2
      echo "  --skip-docker   Skip Docker install (workflows need :host labels or external Docker)"
      echo "  --no-systemd    Do not create/enable act_runner.service"
      echo "  --skip-apt      Skip apt packages and Docker repo setup"
      exit 0
      ;;
    *)
      echo "Unknown option: $arg" >&2
      exit 1
      ;;
  esac
done

if [[ "${EUID:-0}" -ne 0 ]]; then
  echo "This script must run as root (e.g. sudo -E $0 ...)" >&2
  exit 1
fi

arch_raw="$(uname -m)"
case "$arch_raw" in
  x86_64)  ACT_ARCH="amd64" ;;
  aarch64) ACT_ARCH="arm64" ;;
  armv7l)  echo "32-bit ARM is not supported by official act_runner Linux builds." >&2; exit 1 ;;
  *)       echo "Unsupported architecture: $arch_raw" >&2; exit 1 ;;
esac

if [[ "$SKIP_APT" -eq 0 ]]; then
  echo "==> apt: base tools..."
  apt-get update
  apt-get install -y ca-certificates curl gnupg
fi

if [[ "$INSTALL_DOCKER" -eq 1 ]]; then
  if ! command -v docker &>/dev/null; then
    if [[ "$SKIP_APT" -ne 0 ]]; then
      echo "Docker is not installed and --skip-apt was set. Install Docker CE first." >&2
      exit 1
    fi
    echo "==> Installing Docker Engine (get.docker.com)..."
    curl -fsSL https://get.docker.com | sh
  else
    echo "==> Docker already on PATH, skipping get.docker.com."
  fi
fi

if ! id -u "$ACT_RUNNER_USER" &>/dev/null; then
  echo "==> Creating system user $ACT_RUNNER_USER ($ACT_RUNNER_HOME)..."
  useradd --system --create-home --home-dir "$ACT_RUNNER_HOME" --shell /bin/bash "$ACT_RUNNER_USER"
else
  echo "==> User $ACT_RUNNER_USER already exists."
fi

if [[ "$INSTALL_DOCKER" -eq 1 ]]; then
  usermod -aG docker "$ACT_RUNNER_USER"
  systemctl enable --now docker 2>/dev/null || true
fi

mkdir -p /etc/act_runner
chown root:"$ACT_RUNNER_USER" /etc/act_runner
chmod 750 /etc/act_runner

if [[ -z "$ACT_RUNNER_VERSION" ]]; then
  echo "==> Resolving latest act_runner release from gitea.com API..."
  ACT_RUNNER_VERSION="$(
    curl -fsS 'https://gitea.com/api/v1/repos/gitea/act_runner/releases/latest' \
      | sed -n 's/.*"tag_name"[[:space:]]*:[[:space:]]*"v\([^"]*\)".*/\1/p' | head -1
  )"
  if [[ -z "$ACT_RUNNER_VERSION" ]]; then
    echo "Failed to get latest act_runner version. Set ACT_RUNNER_VERSION= manually." >&2
    exit 1
  fi
fi
ACT_VERSION_TAG="v${ACT_VERSION_TAG#v}"
VER_NO_V="${ACT_VERSION_TAG#v}"
DOWNLOAD_URL="https://gitea.com/gitea/act_runner/releases/download/${ACT_VERSION_TAG}/act_runner-${VER_NO_V}-linux-${ACT_ARCH}"

echo "==> Downloading act_runner ${VER_NO_V} for linux-${ACT_ARCH}..."
tmp="$(mktemp)"
curl -fSL -o "$tmp" "$DOWNLOAD_URL"
install -m 0755 -o root -g root "$tmp" "$ACT_RUNNER_BIN"
rm -f "$tmp"
"$ACT_RUNNER_BIN" --version

if [[ -f "$ACT_RUNNER_CONFIG" ]]; then
  echo "==> $ACT_RUNNER_CONFIG already exists, not overwriting."
else
  echo "==> Writing default $ACT_RUNNER_CONFIG ..."
  runuser -u "$ACT_RUNNER_USER" -- "$ACT_RUNNER_BIN" generate-config | install -m 0640 -o root -g "$ACT_RUNNER_USER" /dev/stdin "$ACT_RUNNER_CONFIG"
fi

RUNNER_FILE="${ACT_RUNNER_HOME}/.runner"
if [[ -f "$RUNNER_FILE" ]]; then
  echo "==> $RUNNER_FILE already present; skip register. Remove it to re-register."
else
  if [[ -n "$GITEA_INSTANCE_URL" && -n "$GITEA_RUNNER_REGISTRATION_TOKEN" ]]; then
    echo "==> Registering runner (non-interactive)..."
    # Instance URL should be the public Gitea root URL (same as [server] ROOT_URL for most setups).
    register_args=(-c "$ACT_RUNNER_CONFIG" register --no-interactive
      --instance "$GITEA_INSTANCE_URL"
      --token "$GITEA_RUNNER_REGISTRATION_TOKEN"
    )
    [[ -n "$GITEA_RUNNER_NAME" ]] && register_args+=(--name "$GITEA_RUNNER_NAME")
    if [[ -n "$GITEA_RUNNER_LABELS" ]]; then
      register_args+=(--labels "$GITEA_RUNNER_LABELS")
    fi
    (
      cd "$ACT_RUNNER_HOME"
      runuser -u "$ACT_RUNNER_USER" -- env HOME="$ACT_RUNNER_HOME" \
        "$ACT_RUNNER_BIN" "${register_args[@]}"
    )
  else
    echo "==> No GITEA_INSTANCE_URL + GITEA_RUNNER_REGISTRATION_TOKEN in environment."
    echo "    To register by hand, run (replace URL and token):"
    echo "    runuser -u $ACT_RUNNER_USER -- sh -c 'cd $ACT_RUNNER_HOME && HOME=$ACT_RUNNER_HOME $ACT_RUNNER_BIN -c $ACT_RUNNER_CONFIG register --instance https://gitea/ --token TOKEN ...'"
  fi
fi

chown -R "${ACT_RUNNER_USER}:${ACT_RUNNER_USER}" "$ACT_RUNNER_HOME" 2>/dev/null || true

if [[ ! -f "$RUNNER_FILE" ]]; then
  echo "==> Registration did not create $RUNNER_FILE. Start the service after finishing register."
fi

if [[ "$INSTALL_SYSTEMD" -eq 0 ]]; then
  echo "==> Done (--no-systemd). To run: sudo -u $ACT_RUNNER_USER -H sh -c 'cd $ACT_RUNNER_HOME && HOME=$ACT_RUNNER_HOME $ACT_RUNNER_BIN daemon -c $ACT_RUNNER_CONFIG'"
  exit 0
fi

if [[ "$INSTALL_DOCKER" -eq 1 ]]; then
  SD_AFTER="network.target docker.service"
  SD_WANTS="Wants=network-online.target"
else
  SD_AFTER="network.target"
  SD_WANTS=""
fi

WANTS_BLOCK=""
if [[ -n "${SD_WANTS:-}" ]]; then
  WANTS_BLOCK=$'\n'"$SD_WANTS"
fi

echo "==> Writing /etc/systemd/system/act_runner.service"
cat > /etc/systemd/system/act_runner.service <<UNIT
[Unit]
Description=Gitea Actions act_runner
Documentation=https://gitea.com/gitea/act_runner
After=${SD_AFTER}${WANTS_BLOCK}

[Service]
Type=simple
User=$ACT_RUNNER_USER
Group=$ACT_RUNNER_USER
Environment=HOME=$ACT_RUNNER_HOME
WorkingDirectory=$ACT_RUNNER_HOME
ExecStart=$ACT_RUNNER_BIN daemon --config $ACT_RUNNER_CONFIG
Restart=always
RestartSec=10
TimeoutStartSec=0
# Hardening (tune for your site)
# NoNewPrivileges=yes

[Install]
WantedBy=multi-user.target
UNIT

systemctl daemon-reload
systemctl enable act_runner
if [[ -f "$RUNNER_FILE" ]]; then
  systemctl restart act_runner || systemctl start act_runner
  echo "==> act_runner status:"
  systemctl --no-pager -l status act_runner || true
  echo "==> Logs: journalctl -u act_runner -f"
else
  echo "==> Service installed but not started (no $RUNNER_FILE). After register: systemctl start act_runner"
fi

echo "==> Admin UI: \${GITEA_URL}/-/admin/actions/runners"
