#!/usr/bin/env bash
#
# Daily backup script with grandfather-father-son rotation
# Usage: ./backup_reactor_gfs.sh BACKUP_TARGET_DIR [DAYS_TO_KEEP_DAILY] [--skip-states] [--skip-logs]
#
# Example: ./backup_reactor_gfs.sh $HOME/reactor_data_backups 7
# Keeps: last 7 daily + all monthly + all quarterly backups
#
# This script will back up your states and logs by default. This makes the backups larger,
# but may not be very valuable. To remove either or both, use the skip options shown above.
#
# Recommended: run under cron daily; add this to your user crontab:
#
#    # Back up reactor config and data at 23:55 every night
#    55 23 * * * cd /path/to/reactor && umask 027 && ./tools/backup_reactor_gfs.sh $HOME/reactor_data_backups [other-options]
#
# For more information, try the shell commands "man 1 crontab" and "man 5 crontab".
#

set -euo pipefail

# Below are defaults; do not modify these here. Use command line arguments (see below).
VERSION=26150
DAYS_KEEP_DAILY=30
D_STATES=""
D_LOGS="logs"

# --------------------- Configuration ---------------------
RD=${REACTOR_DATA_PREFIX:-`pwd`}
[ -d ${RD}/config ] || {
    echo "Can't find 'config' in ${RD}";
    echo "This script must be run from the Reactor install/data directory. Example:";
    echo "    cd /home/pi/reactor && tools/backup_reactor_data.sh /home/pi/reactor-backups"
    echo " "
    echo "Docker users: the data directory is where your 'config' folder lives."
    echo " "
    echo "Recommended: run under 'cron'. Please see the script header for instructions."
    exit 1;
}
BACKUP_DIR="${1:?Error: Backup destination directory is required}"
shift
if [ $# -gt 0 ]; then
    if [ "${1:0:2}" != "--" ]; then
        DAYS_KEEP_DAILY="${1:-30}"           # How many daily backups to keep
        shift
    fi
fi
while [ $# -gt 0 ]; do
    case "$1" in
        "--skip-states")
            # Skip the transient state data that is easily rebuild in runtime
            D_STATES="--exclude=storage/states --exclude=storage/entities"
            ;;

        "--skip-logs")
            # Skip the logs
            D_LOGS=""
            ;;

        "--logs-from")
            # If your logs are in a different directory, you can specify that
            shift
            D_LOGS=$1
            ;;

        *)
            echo "Unrecognized command line argument ignored: $1" 2>&1
    esac
    shift
done

# Prefix for backup files (change if you want)
BACKUP_PREFIX="backup"

TIMESTAMP=$(date +"%Y-%m-%d_%H-%M")

# File patterns (do NOT change unless you modify naming scheme below)
DAILY_PATTERN="${BACKUP_PREFIX}-????-??-??_??-??.tar.gz"
MONTHLY_PATTERN="${BACKUP_PREFIX}-????-??.tar.gz"
QUARTERLY_PATTERN="${BACKUP_PREFIX}-????-Q(1|2|3|4).tar.gz"

# --------------------- Validation ---------------------
[[ -d "${RD}/storage" && -d "${RD}/config" ]] || { echo "Error: Please run this script from your Reactor install/data directory."; exit 1; }
[[ ! -d "$BACKUP_DIR" ]] && { mkdir -p "$BACKUP_DIR" || { echo "Cannot create $BACKUP_DIR"; exit 1; } }
[[ ! -w "$BACKUP_DIR" ]] && { echo "Error: Backup directory is not writable: $BACKUP_DIR"; exit 1; }

# --------------------- Functions ---------------------
is_first_day_of_month() {
    [[ $(date +%-d) == "1" ]]
}

is_first_day_of_quarter() {
    local month=$(date +%-m)
    [[ $month == "1" || $month == "4" || $month == "7" || $month == "10" ]] && [[ $(date +%-d) == "1" ]]
}

create_backup() {
    local backup_file="${BACKUP_DIR}/${BACKUP_PREFIX}-${TIMESTAMP}.tar.gz"

    echo
    echo "Creating backup: $backup_file"

    [ -d "${RD}/locales" ] || mkdir -p "${RD}/locales"
    [ -d "${RD}/ext" ] || mkdir -p "${RD}/ext"
    tar -czf "$backup_file" \
            --directory="${RD}" \
            --exclude-vcs --exclude="*/node_modules/*" \
            ${D_STATES} \
            config ext locales ${D_LOGS} storage || {
        echo "Error: Backup creation failed!"
        rm -f "$backup_file" 2>/dev/null
        exit 1
    }

    echo "Backup completed: $(du -h "$backup_file" | cut -f1)"
}

prune_old_backups() {
    echo
    echo "Pruning old daily backups..."

    # 1. Keep all quarterly backups
    # 2. Keep all monthly backups (including quarterly ones)
    # 3. Keep only the newest $DAYS_KEEP_DAILY daily backups

    # Find all daily backups that are NOT monthly
    find "$BACKUP_DIR" -type f -name "$DAILY_PATTERN" ! -name "$MONTHLY_PATTERN" \
        -printf '%T@ %p\n' 2>/dev/null | \
        sort -n | \
        head -n -"$DAYS_KEEP_DAILY" | \
        cut -d' ' -f2- | \
        while read -r file; do
            echo "    Pruning $(basename \"$file\")"
            rm -f "$file"
        done || true
}

# --------------------- Main Logic ---------------------
echo "GFS Backup started at $(date '+%Y-%m-%d %H:%M:%S')"
echo "         Source: ${RD}"
echo "           Dest: ${BACKUP_DIR}"
echo "Daily retention: ${DAYS_KEEP_DAILY} days"
echo "----------------------------------------"

create_backup || exit $?

# Special naming for monthly & quarterly snapshots
Q="${BACKUP_DIR}/${BACKUP_PREFIX}-$(date +%Y)-Q$(date +%q).tar.gz"
[ -f "$Q" ] || {
    # Create/copy as quarterly snapshot
    cp -l "$BACKUP_DIR/${BACKUP_PREFIX}-${TIMESTAMP}.tar.gz" ${Q} 2>/dev/null && \
        echo "Created quarterly snapshot link"
}
M="${BACKUP_DIR}/${BACKUP_PREFIX}-$(date +%Y)-$(date +%m).tar.gz"
[ -f "$M" ] || {
    # Create/copy as monthly snapshot
    cp -l "$BACKUP_DIR/${BACKUP_PREFIX}-${TIMESTAMP}.tar.gz" ${M} 2>/dev/null && \
        echo "Created monthly snapshot link"
}

prune_old_backups

echo "----------------------------------------"
echo "Backup completed successfully at $(date '+%Y-%m-%d %H:%M:%S')"
