#!/bin/bash
# install.sh — one-shot installer for GoatCounter SaaS on the VPS.
#
# Run as the deploy user (with sudo access), from the repo root:
#   cd /path/to/stats.wise-relations.com
#   bash deploy/install.sh [OPTIONS]
#
# Options:
#   --build-on-vps          Clone & build GoatCounter from source on the VPS.
#                           Requires Go 1.22+ (installed by this script via apt).
#   --use-prebuilt PATH     Use a pre-built binary at PATH (default if neither flag given:
#                           script looks for ./goatcounter binary in the repo root).
#   --vhost DOMAIN          Tenant vhost for the first admin site (e.g. admin.stats.wise-relations.com)
#   --email EMAIL           Admin email address
#   --password PASSWORD     Admin password (omit to be prompted interactively)
#   --skip-migrate          Skip DB migration (use if DB already exists and is up to date)
#   --skip-create-site      Skip first site creation (use if site already exists)

set -euo pipefail

# ── Defaults ──────────────────────────────────────────────────────────────────
BUILD_ON_VPS=false
PREBUILT_PATH=""
ADMIN_VHOST=""
ADMIN_EMAIL=""
ADMIN_PASSWORD=""
SKIP_MIGRATE=false
SKIP_CREATE_SITE=false

INSTALL_DIR="/opt/stats"
DATA_DIR="$INSTALL_DIR/data"
BACKUP_DIR="$INSTALL_DIR/backups"
BINARY="$INSTALL_DIR/goatcounter"
DB="sqlite+$DATA_DIR/db.sqlite?_journal_mode=WAL"
SERVICE_USER="stats"
GOATCOUNTER_REPO="https://github.com/arp242/goatcounter.git"
GOATCOUNTER_VERSION="v2"   # branch/tag to build if --build-on-vps

# ── Argument parsing ───────────────────────────────────────────────────────────
while [[ $# -gt 0 ]]; do
    case "$1" in
        --build-on-vps)     BUILD_ON_VPS=true ;;
        --use-prebuilt)     PREBUILT_PATH="$2"; shift ;;
        --vhost)            ADMIN_VHOST="$2"; shift ;;
        --email)            ADMIN_EMAIL="$2"; shift ;;
        --password)         ADMIN_PASSWORD="$2"; shift ;;
        --skip-migrate)     SKIP_MIGRATE=true ;;
        --skip-create-site) SKIP_CREATE_SITE=true ;;
        *) echo "Unknown option: $1" >&2; exit 1 ;;
    esac
    shift
done

# ── Helpers ───────────────────────────────────────────────────────────────────
log()  { echo "[$(date -Iseconds)] $*"; }
die()  { echo "ERROR: $*" >&2; exit 1; }

require_root() {
    if [[ $EUID -ne 0 ]]; then
        die "This script must be run as root (use sudo)."
    fi
}

# ── Step 0: Preflight ─────────────────────────────────────────────────────────
require_root

log "=== GoatCounter SaaS install starting ==="

# ── Step 1: Create system user ────────────────────────────────────────────────
log "Creating system user '$SERVICE_USER'..."
if id "$SERVICE_USER" &>/dev/null; then
    log "  User '$SERVICE_USER' already exists, skipping."
else
    useradd \
        --system \
        --no-create-home \
        --shell /usr/sbin/nologin \
        --comment "GoatCounter SaaS service account" \
        "$SERVICE_USER"
    log "  Created user '$SERVICE_USER'."
fi

# ── Step 2: Create directories ────────────────────────────────────────────────
log "Creating directories..."
mkdir -p "$DATA_DIR" "$BACKUP_DIR"
chown -R "$SERVICE_USER:$SERVICE_USER" "$INSTALL_DIR"
chmod 750 "$INSTALL_DIR" "$DATA_DIR" "$BACKUP_DIR"
log "  $INSTALL_DIR, $DATA_DIR, $BACKUP_DIR — OK."

# ── Step 3: Install Go and build, OR copy pre-built binary ────────────────────
if $BUILD_ON_VPS; then
    log "Installing Go (if not present)..."
    if ! command -v go &>/dev/null; then
        apt-get update -qq
        apt-get install -y --no-install-recommends golang-go git ca-certificates
    fi
    GO_VERSION=$(go version | awk '{print $3}')
    log "  Go: $GO_VERSION"

    BUILD_TMP=$(mktemp -d)
    log "Cloning GoatCounter into $BUILD_TMP..."
    git clone --depth=1 --branch "$GOATCOUNTER_VERSION" "$GOATCOUNTER_REPO" "$BUILD_TMP/goatcounter"
    pushd "$BUILD_TMP/goatcounter" >/dev/null
    log "Building binary (this takes ~2 min on a small VPS)..."
    CGO_ENABLED=1 go build -trimpath -ldflags="-s -w" -o "$BINARY" ./cmd/goatcounter
    popd >/dev/null
    rm -rf "$BUILD_TMP"
    log "  Built and installed to $BINARY."

elif [[ -n "$PREBUILT_PATH" ]]; then
    log "Installing pre-built binary from $PREBUILT_PATH..."
    [[ -f "$PREBUILT_PATH" ]] || die "Binary not found at $PREBUILT_PATH"
    cp "$PREBUILT_PATH" "$BINARY"
    log "  Installed to $BINARY."

else
    # Default: look for the binary in the repo root (local build on dev machine,
    # copied to the VPS via scp / rsync before running install.sh).
    REPO_BINARY="$(dirname "$0")/../goatcounter"
    if [[ -f "$REPO_BINARY" ]]; then
        log "Using binary from repo root: $REPO_BINARY"
        cp "$REPO_BINARY" "$BINARY"
    elif [[ -f "./goatcounter" ]]; then
        log "Using ./goatcounter"
        cp "./goatcounter" "$BINARY"
    else
        die "No binary found. Pass --build-on-vps or --use-prebuilt PATH, or place a 'goatcounter' binary in the repo root."
    fi
fi

chmod 755 "$BINARY"
chown root:root "$BINARY"

# ── Step 4: Install ask-server.py ─────────────────────────────────────────────
log "Installing on-demand TLS ask server..."
cp "$(dirname "$0")/ask-server.py" "$INSTALL_DIR/ask-server.py"
chmod 755 "$INSTALL_DIR/ask-server.py"
chown root:root "$INSTALL_DIR/ask-server.py"

# ── Step 5: Install backup script ─────────────────────────────────────────────
log "Installing backup script..."
cp "$(dirname "$0")/backup.sh" "$INSTALL_DIR/backup.sh"
chmod 750 "$INSTALL_DIR/backup.sh"
chown root:root "$INSTALL_DIR/backup.sh"

# ── Step 6: Install systemd units ─────────────────────────────────────────────
log "Installing systemd service units..."
cp "$(dirname "$0")/stats.service"     /etc/systemd/system/stats.service
cp "$(dirname "$0")/stats-ask.service" /etc/systemd/system/stats-ask.service
systemctl daemon-reload
log "  stats.service and stats-ask.service installed."

# ── Step 7: Environment file ───────────────────────────────────────────────────
ENV_FILE="$INSTALL_DIR/env"
if [[ -f "$ENV_FILE" ]]; then
    log "Environment file $ENV_FILE already exists — leaving it in place."
    log "  Make sure SMTP_URL is set correctly."
else
    log "Creating environment file template at $ENV_FILE..."
    cp "$(dirname "$0")/env.example" "$ENV_FILE"
    chmod 600 "$ENV_FILE"
    chown "$SERVICE_USER:$SERVICE_USER" "$ENV_FILE"
    log "  IMPORTANT: Edit $ENV_FILE and set SMTP_URL before starting the service."
fi

# ── Step 8: Database migration ────────────────────────────────────────────────
if $SKIP_MIGRATE; then
    log "Skipping DB migration (--skip-migrate)."
else
    log "Running database migrations..."
    sudo -u "$SERVICE_USER" "$BINARY" db migrate -db "$DB" all
    log "  Migrations complete."
fi

# ── Step 9: Create first admin site ───────────────────────────────────────────
if $SKIP_CREATE_SITE; then
    log "Skipping site creation (--skip-create-site)."
else
    # Prompt for missing values interactively.
    if [[ -z "$ADMIN_VHOST" ]]; then
        read -rp "Admin site vhost (e.g. admin.stats.wise-relations.com): " ADMIN_VHOST
    fi
    if [[ -z "$ADMIN_EMAIL" ]]; then
        read -rp "Admin email address: " ADMIN_EMAIL
    fi
    if [[ -z "$ADMIN_PASSWORD" ]]; then
        read -rsp "Admin password: " ADMIN_PASSWORD
        echo
    fi

    log "Creating first admin site (vhost=$ADMIN_VHOST, email=$ADMIN_EMAIL)..."
    sudo -u "$SERVICE_USER" "$BINARY" db create site \
        -db "$DB" \
        -vhost "$ADMIN_VHOST" \
        -email "$ADMIN_EMAIL" \
        -password "$ADMIN_PASSWORD"
    log "  Site created."
fi

# ── Step 10: Install cron job for backups ─────────────────────────────────────
log "Installing hourly backup cron job..."
CRON_LINE="0 * * * * root bash $INSTALL_DIR/backup.sh >> /var/log/stats-backup.log 2>&1"
CRON_FILE="/etc/cron.d/stats-backup"
if [[ -f "$CRON_FILE" ]]; then
    log "  Cron file $CRON_FILE already exists — leaving it in place."
else
    echo "$CRON_LINE" > "$CRON_FILE"
    chmod 644 "$CRON_FILE"
    log "  Installed: $CRON_FILE"
fi

# ── Step 11: Enable and start services ────────────────────────────────────────
log "Enabling and starting services..."
systemctl enable --now stats-ask.service
systemctl enable --now stats.service
log "  Both services enabled and started."

# ── Step 12: Health check ─────────────────────────────────────────────────────
log "Waiting for GoatCounter to start (up to 15s)..."
for i in $(seq 1 15); do
    if curl -fsS http://127.0.0.1:8100/status >/dev/null 2>&1; then
        log "  Health check passed after ${i}s."
        break
    fi
    if [[ $i -eq 15 ]]; then
        die "GoatCounter did not respond on http://127.0.0.1:8100/status after 15s. Check: journalctl -u stats -n 50"
    fi
    sleep 1
done

log "Checking ask server..."
if curl -fsS "http://127.0.0.1:8101/ask?domain=stats.wise-relations.com" >/dev/null 2>&1; then
    log "  Ask server health check passed."
else
    die "Ask server did not respond on http://127.0.0.1:8101/ask. Check: journalctl -u stats-ask -n 50"
fi

# ── Done ───────────────────────────────────────────────────────────────────────
cat <<EOF

=== Install complete ===

Next steps:

1. Edit $INSTALL_DIR/env and set SMTP_URL to the real App Password:
     nano $INSTALL_DIR/env
   Then restart the service:
     systemctl restart stats

2. Install the Caddy snippet on the host (Caddy must be running — siehe infra-Repo):
     install -m 0644 deploy/caddy/stats.caddy /etc/caddy/conf.d/stats.caddy
     caddy validate --config /etc/caddy/Caddyfile
     systemctl reload caddy

3. Verify DNS — all of these must resolve to <vps-ip> before traffic flows:
     stats.wise-relations.com
     static.stats.wise-relations.com
     *.stats.wise-relations.com  (wildcard A record)

4. Test signup at https://stats.wise-relations.com

5. Logs: journalctl -u stats -f
          journalctl -u stats-ask -f

EOF
