#!/bin/bash
#
# ferm-systemd - Systemd wrapper for ferm with caching support
# Usage: ferm-systemd {start|stop|reload}
#

set -e

PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

# These should be set by systemd or have defaults
: "${FERM:=/usr/sbin/ferm}"
: "${CONFIG:=/etc/ferm/ferm.conf}"
: "${CACHE_DIR:=/var/cache/ferm}"
: "${CACHE:=no}"
: "${OPTIONS:=}"

# SLOW takes precedence; if not set, initialize from FAST for backwards compatibility
if [ -z "$SLOW" ]; then
    if [ "$FAST" = "no" ]; then
        OPTIONS="$OPTIONS --slow"
    fi
fi

# Parse command
COMMAND=${1:-start}

# Validate cache directory
if [ ! -d "$CACHE_DIR" ] || [ ! -w "$CACHE_DIR" ]; then
    CACHE="no"
fi

# Helper function to check if cache needs regeneration
cache_needs_regen() {
    local CACHE_FILE=$1
    local KERNEL_FILE=$2

    # Check kernel version
    if ! diff /proc/version "$KERNEL_FILE" >/dev/null 2>&1; then
        return 0  # needs regen
    fi

    # Check if cache file exists
    [ ! -f "$CACHE_FILE" ] && return 0

    # Check if config is newer
    [ "$CACHE_FILE" -ot "$CONFIG" ] && return 0

    # Check if any file in /etc/ferm is newer
    [ -n "$(find /etc/ferm -maxdepth 2 -newer "$CACHE_FILE" 2>/dev/null)" ] && return 0

    # Check if systemd unit is newer
    [ -f /etc/systemd/system/ferm.service ] && \
        [ "$CACHE_FILE" -ot /etc/systemd/system/ferm.service ] && return 0

    # Check if ferm binary is newer
    [ "$CACHE_FILE" -ot "$FERM" ] && return 0

    return 1  # cache is valid
}

# Prepare cache and run ferm
prepare_and_run() {
    local CONFIG=${1:-ferm-cache}
    local CACHE_NAME
    CACHE_NAME="$(systemd-escape "$CONFIG")"

    if [ "$CACHE" = "yes" ]; then
        local CACHE_FILE="$CACHE_DIR/$CACHE_NAME.sh"
        local KERNEL_FILE="$CACHE_DIR/$CACHE_NAME.kernel"

        if cache_needs_regen "$CACHE_FILE" "$KERNEL_FILE"; then
            echo "Regenerating ferm cache..."
            rm -f "$CACHE_FILE" "${CACHE_FILE}.tmp" "$KERNEL_FILE"

            $FERM $OPTIONS --shell "$CONFIG" > "${CACHE_FILE}.tmp" || return $?

            cp /proc/version "$KERNEL_FILE"
            mv "${CACHE_FILE}.tmp" "$CACHE_FILE" || return $?
            echo "Cache generated successfully. Now using fresh cache to activate rules"
        else
            echo "Activating firewall rules Using existing ferm cache"
        fi

        # Execute the cached script
        . "$CACHE_FILE" || return $?
    else
        # No caching - run ferm directly
        echo "Activating firewall rules..."
        $FERM $OPTIONS "$CONFIG" || return $?
    fi
}

# Main execution
case "$COMMAND" in
    activate)
        prepare_and_run "$CONFIG" || exit $?
        echo "Firewall rules activated successfully"
        ;;
    deactivate)
        echo "Flushing firewall rules..."
        # For stop, run ferm directly with --flush (don't use/generate cache)
        $FERM $OPTIONS --flush "$CONFIG" || exit $?
        echo "Firewall rules deactivated succesfully"
        ;;
    *)
        echo "Usage: $0 {activate|deactivate}" >&2
        exit 1
        ;;
esac

exit 0
