#!/usr/bin/env bash
# =====================================================================
# WebGIS Database Backup Script
# Location: /opt/webgis-lohne/scripts/backup.sh (on Server)
# Purpose:  Creates compressed pg_dump Backups with daily/weekly/monthly
#           Rotation. Intended to be run via Cron.
# =====================================================================


# Safety Switches
set -euo pipefail

# Logs Error Messages
trap 'echo "[$(date)] ERROR: Script failed at Line ${LINENO} with Exit Code $?."' ERR


# ---------------------------------------------------------------------
# Configuration
# ---------------------------------------------------------------------
DB_HOST="localhost"
DB_PORT="5432"
DB_NAME="webgis-db"
DB_USER="webgis-db-admin"


BACKUP_ROOT="/var/backups/webgis"
BACKUP_DIR_DAILY="${BACKUP_ROOT}/daily"
BACKUP_DIR_WEEKLY="${BACKUP_ROOT}/weekly"
BACKUP_DIR_MONTHLY="${BACKUP_ROOT}/monthly"

# Retention Periods in Days
KEEP_DAILY=7
KEEP_WEEKLY=28
KEEP_MONTHLY=365

# Minimum acceptable Backup File Size in Bytes
# Valid Dumps of even empty Databases are several KBs
MIN_BACKUP_SIZE=10000

# Password is read from  protected File
# pg_dump honors the PGPASSFILE Environment Variable.
export PGPASSFILE="/root/.pgpass_webgis"


# ---------------------------------------------------------------------
# Preflight Checks
# ---------------------------------------------------------------------

# Check pg_dump Availability
if ! command -v pg_dump &> /dev/null; then
    echo "[$(date)] ERROR: pg_dump not found. Install postgresql-client."
    exit 1
fi

# Check Password File Existence and Permissions
if [[ ! -f "${PGPASSFILE}" ]]; then
    echo "[$(date)] ERROR: Password File ${PGPASSFILE} not found."
    exit 1
fi

PGPASS_PERMS=$(stat -c "%a" "${PGPASSFILE}")
if [[ "${PGPASS_PERMS}" != "600" ]]; then
    echo "[$(date)] ERROR: ${PGPASSFILE} has Permissions ${PGPASS_PERMS}, expected 600."
    exit 1
fi


# ---------------------------------------------------------------------
# Preparation
# ---------------------------------------------------------------------
TIMESTAMP=$(date +"%Y-%m-%d_%H-%M-%S")
DAY_OF_WEEK=$(date +"%u")      # 1=Monday ... 7=Sunday
DAY_OF_MONTH=$(date +"%d")

mkdir -p "${BACKUP_DIR_DAILY}" "${BACKUP_DIR_WEEKLY}" "${BACKUP_DIR_MONTHLY}"


# ---------------------------------------------------------------------
# Create Daily Backup in compressed Custom Format
# ---------------------------------------------------------------------
DAILY_FILE="${BACKUP_DIR_DAILY}/webgis_${TIMESTAMP}.dump"

echo "[$(date)] Starting daily Backup -> ${DAILY_FILE}"

pg_dump \
    --host="${DB_HOST}" \
    --port="${DB_PORT}" \
    --username="${DB_USER}" \
    --format=custom \
    --compress=9 \
    --file="${DAILY_FILE}" \
    "${DB_NAME}"

# Verify Backup File Size
BACKUP_SIZE=$(stat -c "%s" "${DAILY_FILE}")
if [[ "${BACKUP_SIZE}" -lt "${MIN_BACKUP_SIZE}" ]]; then
    echo "[$(date)] ERROR: Backup File is only ${BACKUP_SIZE} Bytes (Minimum: ${MIN_BACKUP_SIZE}). Dump probably corrupt."
    exit 1
fi

echo "[$(date)] Daily Backup complete (${BACKUP_SIZE} Bytes)."


# ---------------------------------------------------------------------
# Promote to Weekly Backup on Sundays
# ---------------------------------------------------------------------
if [[ "${DAY_OF_WEEK}" == "7" ]]; then
    cp "${DAILY_FILE}" "${BACKUP_DIR_WEEKLY}/webgis_${TIMESTAMP}.dump"
    echo "[$(date)] Promoted to weekly Backup."
fi


# ---------------------------------------------------------------------
# Promote to Monthly Backup on the First of the Month
# ---------------------------------------------------------------------
if [[ "${DAY_OF_MONTH}" == "01" ]]; then
    cp "${DAILY_FILE}" "${BACKUP_DIR_MONTHLY}/webgis_${TIMESTAMP}.dump"
    echo "[$(date)] Promoted to monthly Backup."
fi


# ---------------------------------------------------------------------
# Rotation: Delete Backups older than Retention Period
# ---------------------------------------------------------------------
find "${BACKUP_DIR_DAILY}"   -name "*.dump" -mtime +${KEEP_DAILY}   -delete
find "${BACKUP_DIR_WEEKLY}"  -name "*.dump" -mtime +${KEEP_WEEKLY}  -delete
find "${BACKUP_DIR_MONTHLY}" -name "*.dump" -mtime +${KEEP_MONTHLY} -delete

echo "[$(date)] Backup Rotation complete."