#!/usr/bin/env bash
#
# Deploy the BigBrainParking Forgejo Actions runner on a host (Ubuntu/Debian).
# Self-contained: installs Docker if missing, writes the runner compose + env,
# registers against git.mowden.top, and starts the runner.
#
# Usage:
#   sudo bash deploy-runner.sh <REGISTRATION_TOKEN> [INSTALL_DIR]
#
#   REGISTRATION_TOKEN  From Forgejo -> hank/BigBrainParking ->
#                       Settings -> Actions -> Runners -> Create new runner.
#   INSTALL_DIR         Where to place the runner (default /opt/bigbrainparking-runner).
#
# Re-running is safe: it updates files and restarts. The token is only consumed
# on the first registration (stored afterwards in <INSTALL_DIR>/data/.runner).
#
# NOTE: this host also runs the Camp Scan runner and several databases on a small
# box (20 GB / 4 cores). The BigBrainParking build workflow hard-caps itself to
# --cpus=2 --memory=8g, but if a Camp Scan build and a BigBrainParking build run
# at the SAME time they'll together want ~4 cores / ~16 GB. Keep an eye on that,
# or lower the caps in .forgejo/workflows/build-apk.yml if the box gets tight.
set -euo pipefail

FORGEJO_INSTANCE="https://git.mowden.top"
RUNNER_IMAGE="code.forgejo.org/forgejo/runner:6.3.1"
RUNNER_NAME="${RUNNER_NAME:-$(hostname)-bigbrainparking}"
JOB_LABEL="docker:docker://node:22-bookworm"

TOKEN="${1:-${REGISTRATION_TOKEN:-}}"
INSTALL_DIR="${2:-/opt/bigbrainparking-runner}"

log() { printf '\033[1;32m==>\033[0m %s\n' "$*"; }
err() { printf '\033[1;31mERROR:\033[0m %s\n' "$*" >&2; }

if [ "$(id -u)" -ne 0 ]; then
  err "Run with sudo/root (needs to install packages and access the Docker socket)."
  exit 1
fi

if [ -z "$TOKEN" ] && [ ! -f "$INSTALL_DIR/data/.runner" ]; then
  err "No registration token given and no existing registration found."
  echo "Usage: sudo bash deploy-runner.sh <REGISTRATION_TOKEN> [INSTALL_DIR]" >&2
  exit 1
fi

# --- 1. Docker ---------------------------------------------------------------
if ! command -v docker >/dev/null 2>&1; then
  log "Installing Docker (get.docker.com)..."
  curl -fsSL https://get.docker.com | sh
  systemctl enable --now docker
else
  log "Docker already installed: $(docker --version)"
fi

if ! docker compose version >/dev/null 2>&1; then
  log "Installing docker compose plugin..."
  apt-get update -y
  apt-get install -y docker-compose-plugin
fi

DOCKER_GID="$(stat -c '%g' /var/run/docker.sock)"
log "Docker socket group id: $DOCKER_GID"

# --- 2. Files ----------------------------------------------------------------
log "Writing runner files to $INSTALL_DIR"
mkdir -p "$INSTALL_DIR/data"
# The runner image runs as uid/gid 1000 and must own its config dir.
chown -R 1000:1000 "$INSTALL_DIR/data"

# Runner config: allow the build workflow to mount the persistent cache volumes
# (Gradle home = Maven deps + build cache, npm cache) so APK builds don't
# redownload and recompile everything each run. Without valid_volumes listed,
# the runner rejects the workflow's `volumes:` and the job fails.
# (No android-sdk volume: the build image already ships the Android SDK/NDK.)
cat > "$INSTALL_DIR/config.yaml" <<'CONFIG'
container:
  valid_volumes:
    - bigbrainparking-gradle
    - bigbrainparking-npm
CONFIG
chown 1000:1000 "$INSTALL_DIR/config.yaml"

# Pre-create the named cache volumes (idempotent).
docker volume create bigbrainparking-gradle >/dev/null
docker volume create bigbrainparking-npm >/dev/null

cat > "$INSTALL_DIR/docker-compose.yml" <<COMPOSE
services:
  runner:
    image: ${RUNNER_IMAGE}
    container_name: bigbrainparking-runner
    restart: unless-stopped
    working_dir: /data
    group_add:
      - "\${DOCKER_GID}"
    volumes:
      - ./data:/data
      - ./config.yaml:/data/config.yaml:ro
      - /var/run/docker.sock:/var/run/docker.sock
    env_file: .env
    command:
      - sh
      - -c
      - |
        if [ ! -f /data/.runner ]; then
          echo "Registering runner with ${FORGEJO_INSTANCE} ..."
          forgejo-runner register --no-interactive \\
            --instance "${FORGEJO_INSTANCE}" \\
            --token "\${REGISTRATION_TOKEN}" \\
            --name "\${RUNNER_NAME}" \\
            --labels "${JOB_LABEL}"
        fi
        exec forgejo-runner daemon --config /data/config.yaml
COMPOSE

# Preserve an existing token line if re-running without a new token.
cat > "$INSTALL_DIR/.env" <<ENV
REGISTRATION_TOKEN=${TOKEN}
RUNNER_NAME=${RUNNER_NAME}
DOCKER_GID=${DOCKER_GID}
ENV
chmod 600 "$INSTALL_DIR/.env"

# --- 3. Start ----------------------------------------------------------------
log "Starting runner..."
cd "$INSTALL_DIR"
docker compose up -d

sleep 6
echo
log "Status:"
docker compose ps --format 'table {{.Name}}\t{{.Status}}'
echo
log "Recent logs (look for 'declared successfully' then 'poller launched'):"
docker compose logs --no-log-prefix 2>&1 | tail -8

cat <<DONE

------------------------------------------------------------------
BigBrainParking runner deployed to $INSTALL_DIR
  Logs:    cd $INSTALL_DIR && docker compose logs -f
  Restart: cd $INSTALL_DIR && docker compose restart
  Stop:    cd $INSTALL_DIR && docker compose down

The signing secrets (ANDROID_KEYSTORE_B64 etc.) are already set on the repo.
Push a tag (e.g. v0.1.3) to trigger the APK build; it runs on THIS host and
reuses the bigbrainparking-gradle / bigbrainparking-npm caches.
------------------------------------------------------------------
DONE
