#!/usr/bin/env bash
# Offsite backup to Backblaze B2 via rclone
# Backs up: all cPanel home dirs, all MySQL databases, WordPress uploads, key configs
# Usage: offsite-backup [--full] [--db-only] [--files-only] [--test]

set -uo pipefail

LOG_FILE="/opt/server-resilience/logs/offsite-backup-$(date +%Y%m%d).log"
CREDS_FILE="/opt/server-resilience/etc/b2-credentials"
LOCK_FILE="/tmp/offsite-backup.lock"
BACKUP_ROOT="/opt/server-resilience/backups/staging"
ALERT_SCRIPT="/opt/server-resilience/bin/send-alert"
MODE="${1:-}"

log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE"; }

# Lock check
if [ -f "$LOCK_FILE" ]; then
    LOCK_PID=$(cat "$LOCK_FILE")
    if kill -0 "$LOCK_PID" 2>/dev/null; then
        log "ERROR: Backup already running (PID $LOCK_PID). Exiting."
        exit 1
    fi
fi
echo $$ > "$LOCK_FILE"
trap "rm -f $LOCK_FILE" EXIT

# Load credentials
if [ ! -f "$CREDS_FILE" ]; then
    log "ERROR: B2 credentials not configured at $CREDS_FILE"
    log "Run: offsite-backup --configure"
    exit 1
fi
source "$CREDS_FILE"

# Validate rclone remote exists
if ! rclone listremotes | grep -q "^b2backup:"; then
    log "ERROR: rclone remote 'b2backup' not configured. Run: offsite-backup --configure"
    exit 1
fi

TIMESTAMP=$(date +%Y%m%d_%H%M%S)
mkdir -p "$BACKUP_ROOT"

backup_databases() {
    log "=== Backing up MySQL databases ==="
    local DB_DUMP_DIR="$BACKUP_ROOT/databases/$TIMESTAMP"
    mkdir -p "$DB_DUMP_DIR"

    # Get all databases
    local DBS
    DBS=$(mysql -u root -e "SHOW DATABASES;" 2>/dev/null | grep -v -E "^(Database|information_schema|performance_schema|sys|mysql)$")

    local COUNT=0
    while IFS= read -r DB; do
        [ -z "$DB" ] && continue
        log "  Dumping: $DB"
        if mysqldump -u root --single-transaction --routines --triggers \
            "$DB" 2>/dev/null | gzip > "$DB_DUMP_DIR/${DB}.sql.gz"; then
            COUNT=$((COUNT+1))
        else
            log "  WARNING: Failed to dump $DB"
        fi
    done <<< "$DBS"

    log "  Uploaded $COUNT databases to B2..."
    rclone sync "$DB_DUMP_DIR" "b2backup:${B2_BUCKET}/databases/${TIMESTAMP}/" \
        --log-level INFO 2>>"$LOG_FILE" && log "  DB backup complete" || \
        { log "ERROR: DB upload failed"; "$ALERT_SCRIPT" "DB Backup Failed" "MySQL backup upload failed at $TIMESTAMP"; }

    # Remove local staging after upload
    rm -rf "$DB_DUMP_DIR"
}

backup_files() {
    log "=== Backing up cPanel home directories ==="

    # Sync each cPanel account home dir to B2
    for USER_HOME in /home/*/; do
        USERNAME=$(basename "$USER_HOME")
        [ "$USERNAME" = "*" ] && continue

        log "  Syncing: $USERNAME"
        rclone sync "$USER_HOME" "b2backup:${B2_BUCKET}/homes/${USERNAME}/" \
            --exclude ".trash/**" \
            --exclude "logs/**" \
            --exclude "tmp/**" \
            --exclude "*.log" \
            --max-age 30d \
            --transfers 4 \
            --log-level NOTICE 2>>"$LOG_FILE" && \
            log "  $USERNAME: done" || \
            log "  WARNING: $USERNAME sync had errors"
    done

    log "=== Backing up key server configs ==="
    local CONF_DUMP="$BACKUP_ROOT/configs/$TIMESTAMP"
    mkdir -p "$CONF_DUMP"

    # Apache/Nginx configs
    cp -r /etc/nginx/conf.d/ "$CONF_DUMP/nginx-conf.d/" 2>/dev/null || true
    cp -r /etc/apache2/ "$CONF_DUMP/apache2/" 2>/dev/null || true
    cp -r /usr/local/apache/conf/userdata/ "$CONF_DUMP/apache-userdata/" 2>/dev/null || true

    # cPanel user/zone configs
    cp -r /var/cpanel/users/ "$CONF_DUMP/cpanel-users/" 2>/dev/null || true
    cp -r /var/named/ "$CONF_DUMP/named-zones/" 2>/dev/null || true

    # Resilience toolkit itself
    cp -r /opt/server-resilience/bin/ "$CONF_DUMP/resilience-bin/" 2>/dev/null || true
    cp -r /opt/server-resilience/etc/ "$CONF_DUMP/resilience-etc/" 2>/dev/null || true

    rclone sync "$CONF_DUMP" "b2backup:${B2_BUCKET}/configs/${TIMESTAMP}/" \
        --log-level NOTICE 2>>"$LOG_FILE" && log "  Configs: done" || \
        log "  WARNING: Config sync had errors"

    rm -rf "$CONF_DUMP"
}

prune_old_backups() {
    log "=== Pruning B2 backups older than 30 days ==="
    # B2 lifecycle rules handle this — but we also clean DB dumps manually
    rclone delete "b2backup:${B2_BUCKET}/databases/" \
        --min-age 30d --log-level NOTICE 2>>"$LOG_FILE" || true
    rclone delete "b2backup:${B2_BUCKET}/configs/" \
        --min-age 30d --log-level NOTICE 2>>"$LOG_FILE" || true
    log "  Pruning done"
}

test_connectivity() {
    log "=== Testing B2 connectivity ==="
    if rclone lsd "b2backup:${B2_BUCKET}/" 2>>"$LOG_FILE"; then
        log "  B2 connectivity: OK"
        return 0
    else
        log "  ERROR: Cannot reach B2 bucket ${B2_BUCKET}"
        return 1
    fi
}

# Main
log "============================================"
log "Offsite Backup Started — mode: ${MODE:-full}"
log "============================================"

case "$MODE" in
    --configure)
        cat << 'EOF'
To configure B2 credentials, run:
  rclone config

Choose: n (new remote) → name it "b2backup" → type "b2" → enter keyID and applicationKey

Then create /opt/server-resilience/etc/b2-credentials with:
  B2_BUCKET=your-bucket-name

EOF
        ;;
    --test)
        test_connectivity
        ;;
    --db-only)
        test_connectivity && backup_databases
        ;;
    --files-only)
        test_connectivity && backup_files
        ;;
    *)
        # Full backup
        if test_connectivity; then
            backup_databases
            backup_files
            prune_old_backups
            log "=== Backup Complete ==="
            "$ALERT_SCRIPT" "Backup OK" "Offsite backup completed successfully at $TIMESTAMP" 2>/dev/null || true
        else
            "$ALERT_SCRIPT" "Backup FAILED" "Cannot reach B2 — offsite backup did not run at $TIMESTAMP"
            exit 1
        fi
        ;;
esac
