#!/bin/bash
#author: gobonja

[ "$(findmnt / -no fstype)" == "overlay" ] && { echo "==> skipping timeshift-autosnap because system is booted in Live CD mode..."; exit 0; }

[[ -v SKIP_AUTOSNAP ]] && { echo "==> skipping timeshift-autosnap due SKIP_AUTOSNAP environment variable being set."; exit 0; }

readonly CONF_FILE=/etc/timeshift-autosnap.conf
readonly SNAPSHOTS_TO_DELETE=$(mktemp -u --tmpdir "${0##*/}.XXXXXXXX")
readonly SNAPSHOT_NAME_DATE_PATTERN="[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}_[0-9]\{2\}-[0-9]\{2\}-[0-9]\{2\}"

get_latest_snapshot_timestamp() {
    local snapshot=$(timeshift --list | grep "$SNAPSHOT_DESCRIPTION" | tail -n 1)
    local snapshot_date=$(echo "$snapshot" | sed -n "s/.*\($SNAPSHOT_NAME_DATE_PATTERN\).*/\1/p")
    
    if [[ -n "$snapshot_date" ]]; then
        local formatted_date=$(echo "$snapshot_date" | sed 's/_/ /' | sed 's/-/:/3g')
        date -d "$formatted_date" +%s 2>/dev/null || echo ""
    else
        echo ""
    fi
}

get_property() {
    if [ ! -f "$CONF_FILE" ]; then
        echo "$CONF_FILE not found! Using $1=$3" >&2;
        param_value=$3
    else
        param_value=$(sed '/^\#/d' $CONF_FILE | grep "$1" | tail -n 1 |\
            cut -d "=" -f2- | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')

        if { [ "$2" == "boolean" ] && [ "$param_value" != true ] && [ "$param_value" != false ]; } || \
           { [ "$2" == "integer" ] && [[ ! "$param_value" =~ ^[-+]?([1-9][[:digit:]]*|1)$ ]]; } || \
           { [ "$2" == "non-negative-integer" ] && [[ ! "$param_value" =~ ^[0-9]+$ ]]; } || \
           { [ "$2" == "string" ] && [ "$param_value" == "" ]; } ; then
            echo "Wrong paramater in $CONF_FILE. Using $1=$3" >&2
            param_value=$3
        fi
    fi

    echo "$param_value"
}

if $(get_property "skipAutosnap" "boolean" "false"); then
    echo "==> skipping timeshift-autosnap due skipAutosnap in $CONF_FILE set to TRUE." >&2; exit 0;
fi

if $(get_property "skipRsyncAutosnap" "boolean" "false") && ! [ $(findmnt / -no fstype) == "btrfs" ] ; then
    echo "==> skipping timeshift-autosnap due skipRsyncAutosnap in $CONF_FILE set to TRUE." >&2; exit 0;
fi

readonly SNAPSHOT_DESCRIPTION=$(get_property "snapshotDescription" "string" "{timeshift-autosnap} {created before upgrade}")
readonly MIN_HOURS_BETWEEN_SNAPSHOTS=$(get_property "minHoursBetweenSnapshots" "non-negative-integer" "18")

last_snapshot_timestamp=$(get_latest_snapshot_timestamp)
current_timestamp=$(date +%s)

if [[ -n "$last_snapshot_timestamp" ]]; then
    hours_since_last_snapshot=$(( (current_timestamp - last_snapshot_timestamp) / 3600 ))

    if [[ "$hours_since_last_snapshot" -lt "$MIN_HOURS_BETWEEN_SNAPSHOTS" ]]; then
        echo "==> Skipping timeshift-autosnap because only $hours_since_last_snapshot hours have passed since the last snapshot." >&2
        exit 0
    fi
fi

timeshift --create --comments "$SNAPSHOT_DESCRIPTION${1:+ "$1"}" || { echo "Unable to run timeshift-autosnap! Please close Timeshift and try again. Script will now exit..." >&2; exit 1; }

if $(get_property "deleteSnapshots" "boolean" "true"); then
    timeshift --list > "$SNAPSHOTS_TO_DELETE"
    sed -ni "/$SNAPSHOT_DESCRIPTION/p" "$SNAPSHOTS_TO_DELETE"
    sed -ni "s/.*\($SNAPSHOT_NAME_DATE_PATTERN\).*/\1/p" "$SNAPSHOTS_TO_DELETE"

    count=$(($(sed -n '$=' "$SNAPSHOTS_TO_DELETE")-$(get_property "maxSnapshots" "integer" "3")))

    if [ "$count" -gt 0 ] ; then
        sed -i ${count}q "$SNAPSHOTS_TO_DELETE"

        for snapshot in $(cat "$SNAPSHOTS_TO_DELETE"); do
            timeshift --delete --snapshot "$snapshot"
        done
    fi
fi;

if $(get_property "updateGrub" "boolean" "true") && [ -f /etc/grub.d/41_snapshots-btrfs ]; then

    if systemctl is-active --quiet grub-btrfsd.service; then
        echo "==> grub-btrfsd service is running. Skipping GRUB update to prevent "
        echo "==> race condition between timeshift-autosnap and grub-btrfsd service"
        echo "==> Set 'updateGrub=false' in $CONF_FILE or stop grub-btrfsd service."
    else
        . /etc/default/grub-btrfs/config
        
        if [ -s "${GRUB_BTRFS_GRUB_DIRNAME:-/boot/grub}/grub-btrfs.cfg" ]; then /etc/grub.d/41_snapshots-btrfs; else ${GRUB_BTRFS_MKCONFIG:-grub-mkconfig} -o ${GRUB_BTRFS_GRUB_DIRNAME:-/boot/grub}/grub.cfg; fi 
    fi
fi

exit 0
