#!/bin/bash

# ==========================================
# INTERACTIVE FIREWALL CONFIGURATOR FOR SAP B1
# (With Save/Load State)
# ==========================================

# Configuration File
CONFIG_FILE="./firewall_state.conf"

# Colors for formatting
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color

# ==========================================
# SERVICE DEFINITIONS
# ==========================================
declare -a SVC_NAMES
declare -a SVC_PORTS

SVC_NAMES[0]="SAP Web Client"
SVC_PORTS[0]="443"

SVC_NAMES[1]="SAP HANA Database (System & Company DB)"
SVC_PORTS[1]="30013 30015"

SVC_NAMES[2]="SAP Business One SLD"
SVC_PORTS[2]="40000 40001 40002 40003 40004 40005"

SVC_NAMES[3]="SAP Business One Auth"
SVC_PORTS[3]="40020"

SVC_NAMES[4]="SAP Business One Service Layer, Cockpit"
SVC_PORTS[4]="50000 4300"

SVC_NAMES[5]="SAP Host Agent"
SVC_PORTS[5]="1128 1129"

SVC_NAMES[6]="SSH Remote Access"
SVC_PORTS[6]="22"

SVC_NAMES[7]="SMB / B1_SHR (File Sharing)"
SVC_PORTS[7]="139 445"

# Arrays to store user decisions
declare -a CONFIG_DECISION # "ALL", "IP", "SKIP"
declare -a CONFIG_IPS      # Stores the IP string if "IP" is chosen
DO_FLUSH=false

# ==========================================
# HELPER FUNCTIONS
# ==========================================

print_header() {
    clear
    echo -e "${CYAN}==========================================${NC}"
    echo -e "${CYAN}   SAP B1 Interactive Firewall Setup      ${NC}"
    echo -e "${CYAN}==========================================${NC}"
    echo ""
}

save_config() {
    echo "# SAP B1 Firewall State - Do not edit manually unless you know what you are doing" > "$CONFIG_FILE"
    for i in "${!SVC_NAMES[@]}"; do
        # Use simple variable assignment format
        echo "SAVED_DECISION[$i]=\"${CONFIG_DECISION[$i]}\"" >> "$CONFIG_FILE"
        echo "SAVED_IPS[$i]=\"${CONFIG_IPS[$i]}\"" >> "$CONFIG_FILE"
    done
    echo "Config state saved to $CONFIG_FILE"
}

load_config() {
    if [ -f "$CONFIG_FILE" ]; then
        echo -e "${GREEN}Found saved configuration file.${NC}"
        source "$CONFIG_FILE"
        # Map SAVED variables to current CONFIG variables
        for i in "${!SVC_NAMES[@]}"; do
            CONFIG_DECISION[$i]="${SAVED_DECISION[$i]}"
            CONFIG_IPS[$i]="${SAVED_IPS[$i]}"
        done
        return 0
    else
        return 1
    fi
}

# ==========================================
# INITIAL SETUP
# ==========================================
print_header

# 1. Flush Question (First)
echo -e "${YELLOW}Existing Configuration:${NC}"
echo "Do you want to FLUSH (remove) all currently active firewall rules before starting?"
echo "This ensures a clean slate. (Only affects Runtime, not Permanent config)"
read -p "Flush all current rules? [Y/n]: " flush_choice
flush_choice=${flush_choice:-Y} # Default to Yes

if [[ "$flush_choice" =~ ^[Yy]$ ]]; then
    DO_FLUSH=true
    echo -e "-> ${RED}Will flush all rules (Clean Slate).${NC}"
else
    echo -e "-> Keeping existing rules (Appending new ones)."
fi
echo ""
sleep 1

# 2. Load Configuration (Second)
HAS_CONFIG=false
if load_config; then
    HAS_CONFIG=true
    echo "Previous settings loaded. You can press ENTER to accept defaults during selection."
else
    echo "No previous configuration found. Starting fresh."
fi
echo ""
sleep 1

# ==========================================
# CONFIGURATION LOOP
# ==========================================

print_header
echo -e "This script will help you configure access rules for each service."
echo -e "${YELLOW}Note: Configuration applies to RUNTIME only.${NC}"
echo ""

for i in "${!SVC_NAMES[@]}"; do
    NAME="${SVC_NAMES[$i]}"
    PORTS="${SVC_PORTS[$i]}"
    
    # Get previous setting if available
    PREV_DECISION="${CONFIG_DECISION[$i]}"
    PREV_IPS="${CONFIG_IPS[$i]}"
    
    # Determine default option number for UI
    DEFAULT_OPT=""
    DEFAULT_TXT=""
    if [[ "$PREV_DECISION" == "ALL" ]]; then DEFAULT_OPT="1"; DEFAULT_TXT="[Default: 1 - Public]"; fi
    if [[ "$PREV_DECISION" == "IP" ]];  then DEFAULT_OPT="2"; DEFAULT_TXT="[Default: 2 - Restricted]"; fi
    if [[ "$PREV_DECISION" == "SKIP" ]]; then DEFAULT_OPT="3"; DEFAULT_TXT="[Default: 3 - Skip]"; fi

    echo -e "--------------------------------------------------"
    echo -e "Configuring Service: ${GREEN}$NAME${NC}"
    echo -e "Ports: ${YELLOW}$PORTS${NC}"
    echo "--------------------------------------------------"
    echo "1) Allow from ANYWHERE (Public)"
    echo "2) Restrict to SPECIFIC IPs"
    echo "3) Skip / Block (Do not open)"
    
    while true; do
        read -p "Select option (1-3) $DEFAULT_TXT: " choice
        
        # Handle Enter key (Default)
        if [[ -z "$choice" && -n "$DEFAULT_OPT" ]]; then
            choice=$DEFAULT_OPT
        fi

        case $choice in
            1)
                CONFIG_DECISION[$i]="ALL"
                CONFIG_IPS[$i]=""
                echo -e "-> Selected: ${RED}Public Access${NC}"
                break
                ;;
            2)
                CONFIG_DECISION[$i]="IP"
                echo ""
                echo -e "Enter IPs or Subnets separated by spaces or commas."
                
                # Show previous IPs as default if they exist
                if [[ -n "$PREV_IPS" ]]; then
                    echo -e "Current Saved IPs: ${CYAN}$PREV_IPS${NC}"
                    read -p "IPs [Press Enter to keep current]: " ip_input
                    if [[ -z "$ip_input" ]]; then
                        ip_input="$PREV_IPS"
                    fi
                else
                    echo -e "Example: ${CYAN}192.168.1.10, 192.168.1.20${NC}"
                    read -p "IPs: " ip_input
                fi

                # Replace commas with spaces to sanitize
                CONFIG_IPS[$i]="${ip_input//,/ }"
                echo -e "-> Selected: ${GREEN}Restricted to ${CONFIG_IPS[$i]}${NC}"
                break
                ;;
            3)
                CONFIG_DECISION[$i]="SKIP"
                CONFIG_IPS[$i]=""
                echo -e "-> Selected: ${YELLOW}Skipping${NC}"
                break
                ;;
            *)
                echo "Invalid option."
                ;;
        esac
    done
    echo ""
done

# ==========================================
# SUMMARY & CONFIRMATION
# ==========================================

print_header
echo -e "${YELLOW}SUMMARY OF PENDING CHANGES:${NC}"
echo ""
printf "%-25s | %-15s | %-30s\n" "Service" "Action" "Details"
echo "-------------------------------------------------------------------------------"

for i in "${!SVC_NAMES[@]}"; do
    NAME="${SVC_NAMES[$i]}"
    ACTION="${CONFIG_DECISION[$i]}"
    DETAILS="${CONFIG_IPS[$i]}"
    
    # Shorten name for table
    SHORT_NAME=${NAME:0:24}

    if [ "$ACTION" == "ALL" ]; then
        printf "%-25s | ${RED}%-15s${NC} | %-30s\n" "$SHORT_NAME" "Open Public" "0.0.0.0/0"
    elif [ "$ACTION" == "IP" ]; then
        printf "%-25s | ${GREEN}%-15s${NC} | %-30s\n" "$SHORT_NAME" "Restricted" "$DETAILS"
    else
        printf "%-25s | ${YELLOW}%-15s${NC} | %-30s\n" "$SHORT_NAME" "Blocked/Skip" "-"
    fi
done

echo ""
echo -e "${CYAN}Global Actions:${NC}"
if [ "$DO_FLUSH" = true ]; then
    echo "1. FLUSH ALL current rules (Clean Slate)."
else
    echo "1. Remove specific insecure rules (0-65535) and standard SSH service."
fi
echo ""

read -p "Do you want to SAVE config and APPLY changes now? [Y/n]: " confirm
confirm=${confirm:-Y} # Default to Yes

if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
    echo "Aborted."
    exit 0
fi

# ==========================================
# EXECUTION
# ==========================================
echo ""
echo "Saving configuration to $CONFIG_FILE..."
save_config

echo "Applying configurations (RUNTIME ONLY)..."

# 1. Flush or Safety Cleanup
if [ "$DO_FLUSH" = true ]; then
    echo "-> Flushing active rules..."
    # Flush Services
    for service in $(firewall-cmd --list-services); do
        firewall-cmd --remove-service="$service" >/dev/null 2>&1
    done
    # Flush Ports
    for port in $(firewall-cmd --list-ports); do
        firewall-cmd --remove-port="$port" >/dev/null 2>&1
    done
    # Flush Rich Rules
    firewall-cmd --list-rich-rules | while read -r rule; do
        if [ -n "$rule" ]; then
            firewall-cmd --remove-rich-rule="$rule" >/dev/null 2>&1
        fi
    done
else
    # Only remove specific conflicting rules if not flushing everything
    echo "-> Cleaning up insecure rules..."
    firewall-cmd --remove-port=0-65535/tcp >/dev/null 2>&1
    firewall-cmd --remove-service=ssh >/dev/null 2>&1
    firewall-cmd --remove-port=22/tcp >/dev/null 2>&1
fi

# 2. Loop and Apply
for i in "${!SVC_NAMES[@]}"; do
    PORTS="${SVC_PORTS[$i]}"
    DECISION="${CONFIG_DECISION[$i]}"
    
    # Convert space-separated ports to array for inner loop
    read -ra PORT_ARR <<< "$PORTS"

    if [ "$DECISION" == "ALL" ]; then
        # Open ports globally
        for port in "${PORT_ARR[@]}"; do
            echo "   Opening $port globally..."
            firewall-cmd --add-port=${port}/tcp >/dev/null
        done

    elif [ "$DECISION" == "IP" ]; then
        # Add rich rules for specific IPs
        read -ra IP_ARR <<< "${CONFIG_IPS[$i]}"
        
        for ip in "${IP_ARR[@]}"; do
            if [[ -z "$ip" ]]; then continue; fi
            for port in "${PORT_ARR[@]}"; do
                echo "   Allowing $ip access to port $port..."
                firewall-cmd --add-rich-rule="rule family='ipv4' source address='$ip' port port='$port' protocol='tcp' accept" >/dev/null
            done
        done
    fi
done

echo ""
echo -e "${YELLOW}==========================================${NC}"
echo -e "${YELLOW}   TESTING CONNECTIVITY                   ${NC}"
echo -e "${YELLOW}==========================================${NC}"
echo "The new rules are active. If you are locked out, DO NOTHING."
echo "The firewall will automatically REVERT in 15 seconds."
echo ""
echo -e "${GREEN}If you can read this and your connection works:${NC}"
echo -e "Press ${CYAN}ENTER${NC} now to CONFIRM and KEEP the changes."
echo "OR press Ctrl+C to keep changes without saving (script exits)."
echo ""

if read -t 15 -p "Waiting for confirmation... "; then
    # User pressed Enter (Connection is good)
    echo ""
    echo -e "${GREEN}Connection confirmed!${NC}"
    echo ""
    read -p "Do you want to save these rules PERMANENTLY now? [Y/n]: " save_choice
    save_choice=${save_choice:-Y} # Default to Yes
    
    if [[ "$save_choice" =~ ^[Yy]$ ]]; then
        echo "Saving to permanent configuration..."
        firewall-cmd --runtime-to-permanent
        echo -e "${GREEN}Configuration Saved.${NC}"
    else
        echo "Rules kept in RUNTIME only. They will be lost on reboot."
    fi
else
    # Timeout occurred (User likely locked out)
    echo ""
    echo -e "${RED}Timeout reached! Reverting changes...${NC}"
    
    # Revert Logic
    echo "1. Reloading permanent configuration..."
    firewall-cmd --reload >/dev/null 2>&1
    
    echo "2. Ensuring SSH is accessible (Failsafe)..."
    firewall-cmd --add-service=ssh >/dev/null 2>&1
    
    echo -e "${YELLOW}Firewall reverted to previous state (plus global SSH allow).${NC}"
fi

exit 0