#!/usr/bin/env bash
# ============================================================================
# Install a Gitea Actions runner (act_runner) on THIS host for tlam89/sciagent.
# Target: the Gitea + app box 103.149.170.102 (run this ON that box, as root).
#
# Registers ONE runner with two labels so the CI/CD pipeline can use both:
#   ci      -> docker mode  (clean ephemeral containers; backend + frontend jobs)
#   deploy  -> host  mode   (runs on the host so it can drive `docker compose`)
#
# Prereqs installed/verified here: Docker + compose plugin, Node.js (needed by
# host-mode actions/checkout). Re-runnable: skips steps already done.
#
# Usage (token already minted for this repo; rotate via Gitea if it expires):
#   sudo bash setup-gitea-runner.sh
# Override:
#   GITEA_URL=http://localhost:3000 RUNNER_TOKEN=xxx bash setup-gitea-runner.sh
# ============================================================================
set -euo pipefail

GITEA_URL="${GITEA_URL:-http://localhost:3000}"
RUNNER_TOKEN="${RUNNER_TOKEN:-aCd3rpPnJTAPVHqsTIme9SaJm3pUbnbyOQqMrt9O}"
RUNNER_NAME="${RUNNER_NAME:-sciagent-box-runner}"
RUNNER_LABELS="${RUNNER_LABELS:-ci:docker://catthehacker/ubuntu:act-22.04,deploy:host}"
ACT_VERSION="${ACT_VERSION:-0.2.11}"
RUNNER_DIR="${RUNNER_DIR:-/opt/act_runner}"

log(){ printf '\n\033[36m==> %s\033[0m\n' "$*"; }

[[ "$(id -u)" -eq 0 ]] || { echo "Run as root (sudo)."; exit 1; }

# --- 1. Docker + compose plugin --------------------------------------------
if ! command -v docker >/dev/null 2>&1; then
  log "Installing Docker (get.docker.com convenience script)"
  curl -fsSL https://get.docker.com | sh
fi
if ! docker compose version >/dev/null 2>&1; then
  log "docker compose plugin missing — installing docker-compose-plugin"
  (apt-get update && apt-get install -y docker-compose-plugin) || \
    echo "WARN: install the compose plugin manually for your distro."
fi
systemctl enable --now docker >/dev/null 2>&1 || true
docker version --format '{{.Server.Version}}' >/dev/null 2>&1 || { echo "Docker daemon not running"; exit 1; }

# --- 2. Node.js (host-mode jobs run actions/checkout, which needs node) -----
if ! command -v node >/dev/null 2>&1; then
  log "Installing Node.js 20"
  curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && apt-get install -y nodejs || \
    echo "WARN: install Node.js 20 manually if your distro is non-Debian."
fi

# --- 3. Download act_runner -------------------------------------------------
mkdir -p "$RUNNER_DIR"
cd "$RUNNER_DIR"
if [[ ! -x "$RUNNER_DIR/act_runner" ]]; then
  log "Downloading act_runner ${ACT_VERSION}"
  arch="$(uname -m)"; case "$arch" in x86_64) arch=amd64;; aarch64) arch=arm64;; esac
  curl -fsSL -o act_runner \
    "https://dl.gitea.com/act_runner/${ACT_VERSION}/act_runner-${ACT_VERSION}-linux-${arch}"
  chmod +x act_runner
fi

# --- 4. Register ------------------------------------------------------------
if [[ ! -f "$RUNNER_DIR/.runner" ]]; then
  log "Registering with Gitea ($GITEA_URL) labels: $RUNNER_LABELS"
  ./act_runner register --no-interactive \
    --instance "$GITEA_URL" \
    --token "$RUNNER_TOKEN" \
    --name "$RUNNER_NAME" \
    --labels "$RUNNER_LABELS"
else
  log ".runner already exists — skipping register"
fi
[[ -f "$RUNNER_DIR/config.yaml" ]] || ./act_runner generate-config > config.yaml

# generate-config injects DEFAULT labels (ubuntu-latest/22.04/20.04) into config.yaml
# which OVERRIDE the --labels passed at registration. Force our labels into config.yaml
# so the daemon advertises ci (docker) + deploy (host), not the defaults.
python3 - "$RUNNER_DIR/config.yaml" "$RUNNER_LABELS" <<'PY'
import sys,re
path,labels=sys.argv[1],sys.argv[2].split(",")
s=open(path).read().splitlines(keepends=True)
o=[];i=0;n=len(s);done=False
while i<n:
    if not done and re.match(r'^\s{2}labels:\s*$',s[i]):
        o.append("  labels:\n")
        for x in labels: o.append('    - "%s"\n'%x)
        i+=1
        while i<n and re.match(r'^\s{4}(- |#)',s[i]): i+=1
        done=True; continue
    o.append(s[i]); i+=1
if not done:
    o2=[];ins=False
    for line in o:
        o2.append(line)
        if not ins and re.match(r'^runner:\s*$',line):
            o2.append("  labels:\n")
            for x in labels: o2.append('    - "%s"\n'%x)
            ins=True
    o=o2
open(path,"w").write("".join(o))
print("config.yaml labels ->", ", ".join(labels))
PY

# --- 5. systemd service -----------------------------------------------------
log "Installing systemd service act_runner"
cat > /etc/systemd/system/act_runner.service <<UNIT
[Unit]
Description=Gitea Actions runner (sciagent)
After=docker.service network-online.target
Wants=docker.service

[Service]
WorkingDirectory=${RUNNER_DIR}
ExecStart=${RUNNER_DIR}/act_runner daemon --config ${RUNNER_DIR}/config.yaml
Restart=always
RestartSec=5
User=root

[Install]
WantedBy=multi-user.target
UNIT

systemctl daemon-reload
systemctl enable --now act_runner
sleep 3
systemctl --no-pager --full status act_runner | head -12

echo
echo "Done. Verify in Gitea: Repo → Settings → Actions → Runners — '$RUNNER_NAME' should be Online."
echo "Logs: journalctl -u act_runner -f"
