#!/bin/bash

# Exit immediately if a command exits with a non-zero status
set -e

export DEBIAN_FRONTEND=noninteractive

# Helper function to read input interactively even when script is executed via curl pipe
prompt_read() {
    local prompt_text="$1"
    local var_name="$2"
    if [ -t 0 ]; then
        read -r -p "$prompt_text" "$var_name"
    elif [ -e /dev/tty ]; then
        read -r -p "$prompt_text" "$var_name" < /dev/tty
    else
        read -r -p "$prompt_text" "$var_name"
    fi
}

echo "=== 1. Basic packages installation ==="
sudo DEBIAN_FRONTEND=noninteractive apt-get update -y
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y nano curl

echo -e "\n=== 2. Enabling swap of 4GB ==="
current_swap_mb=$(free -m | awk '/^Swap:/ {print $2}')
if [ -z "$current_swap_mb" ]; then
    current_swap_mb=0
fi

swapfile_size=0
if [ -f /swapfile ]; then
    swapfile_size=$(stat -c %s /swapfile 2>/dev/null || echo 0)
fi

target_swap_bytes=4294967296

if [ "$current_swap_mb" -ge 3900 ]; then
    echo "Swap of 4GB is already active (${current_swap_mb} MB total). Skipping swap setup."
elif [ -f /swapfile ] && [ "$swapfile_size" -eq "$target_swap_bytes" ]; then
    echo "/swapfile of 4GB already exists. Enabling swap..."
    sudo swapon /swapfile 2>/dev/null || true
    if ! grep -q '/swapfile swap swap defaults 0 0' /etc/fstab; then
        echo '/swapfile swap swap defaults 0 0' | sudo tee -a /etc/fstab
    fi
    echo "Swap enabled."
else
    echo "Configuring 4GB swap..."
    sudo swapoff -a || true
    sudo rm -f /swapfile
    sudo fallocate -l 4G /swapfile
    sudo chmod 600 /swapfile
    sudo mkswap /swapfile
    sudo swapon /swapfile
    if ! grep -q '/swapfile swap swap defaults 0 0' /etc/fstab; then
        echo '/swapfile swap swap defaults 0 0' | sudo tee -a /etc/fstab
    fi
    echo "4GB swap configured and enabled."
fi

echo -e "\n=== 3. Allow root ssh login and insert public key ==="
prompt_read "Please paste the public key to add for root ssh access: " pub_key

# Update sshd_config to allow root login and pubkey authentication
sudo sed -i 's/^#*PermitRootLogin.*/PermitRootLogin yes/' /etc/ssh/sshd_config
sudo sed -i 's/^#*PubkeyAuthentication.*/PubkeyAuthentication yes/' /etc/ssh/sshd_config

# Setup root's authorized_keys
sudo mkdir -p /root/.ssh
sudo chmod 700 /root/.ssh

# For oracle instances, comment out the first line if it exists and contains restrictions
if sudo test -f /root/.ssh/authorized_keys; then
    sudo sed -i '1s/^[^#]/#&/' /root/.ssh/authorized_keys
fi

# Append the provided public key
if [ -n "$pub_key" ]; then
    echo "$pub_key" | sudo tee -a /root/.ssh/authorized_keys > /dev/null
    sudo chmod 600 /root/.ssh/authorized_keys
fi

sudo service ssh restart
echo "SSH service restarted."

echo -e "\n=== 4. Basic iptables firewall setup ==="
prompt_read "Do you want to set up iptables firewall? (y/n): " setup_iptables
if [[ "$setup_iptables" =~ ^[Yy]$ ]]; then
    # Preseed debconf so iptables-persistent install does not prompt interactively
    echo iptables-persistent iptables-persistent/autosave_v4 boolean true | sudo debconf-set-selections
    echo iptables-persistent iptables-persistent/autosave_v6 boolean true | sudo debconf-set-selections
    sudo DEBIAN_FRONTEND=noninteractive apt-get install -y iptables iptables-persistent netfilter-persistent

    # Set default policies to ACCEPT temporarily while applying rules to prevent lockout
    sudo iptables -P INPUT ACCEPT
    sudo iptables -P FORWARD ACCEPT
    sudo iptables -P OUTPUT ACCEPT

    # Flush existing rules and custom chains
    sudo iptables -F
    sudo iptables -X
    sudo iptables -t nat -F 2>/dev/null || true
    sudo iptables -t nat -X 2>/dev/null || true
    sudo iptables -t mangle -F 2>/dev/null || true
    sudo iptables -t mangle -X 2>/dev/null || true

    # Allow loopback interface
    sudo iptables -A INPUT -i lo -j ACCEPT

    # Allow established and related connections
    sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

    # Allow ICMP (ping)
    sudo iptables -A INPUT -p icmp -j ACCEPT

    # Allow SSH (22) and HTTP (80)
    sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT
    sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT

    prompt_read "Do you want to allow HTTPS (port 443)? (y/n): " allow_https
    if [[ "$allow_https" =~ ^[Yy]$ ]]; then
        sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT
    fi

    # Set default drop policies for incoming and forward traffic
    sudo iptables -P INPUT DROP
    sudo iptables -P FORWARD DROP
    sudo iptables -P OUTPUT ACCEPT

    # IPv6 rules configuration
    if command -v ip6tables >/dev/null 2>&1; then
        sudo ip6tables -P INPUT ACCEPT
        sudo ip6tables -P FORWARD ACCEPT
        sudo ip6tables -P OUTPUT ACCEPT
        sudo ip6tables -F
        sudo ip6tables -X
        sudo ip6tables -A INPUT -i lo -j ACCEPT
        sudo ip6tables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
        sudo ip6tables -A INPUT -p ipv6-icmp -j ACCEPT
        sudo ip6tables -A INPUT -p tcp --dport 22 -j ACCEPT
        sudo ip6tables -A INPUT -p tcp --dport 80 -j ACCEPT
        if [[ "$allow_https" =~ ^[Yy]$ ]]; then
            sudo ip6tables -A INPUT -p tcp --dport 443 -j ACCEPT
        fi
        sudo ip6tables -P INPUT DROP
        sudo ip6tables -P FORWARD DROP
        sudo ip6tables -P OUTPUT ACCEPT
    fi

    # Save rules and enable persistence across reboots
    sudo mkdir -p /etc/iptables
    sudo iptables-save | sudo tee /etc/iptables/rules.v4 > /dev/null
    if command -v ip6tables-save >/dev/null 2>&1; then
        sudo ip6tables-save | sudo tee /etc/iptables/rules.v6 > /dev/null
    fi
    sudo netfilter-persistent save
    sudo systemctl enable netfilter-persistent

    echo -e "\nActive IPv4 iptables rules:"
    sudo iptables -L -n -v --line-numbers
else
    echo "Skipping iptables setup."
fi

echo -e "\n=== 5. Helper function for opening ports ==="
prompt_read "Do you want to install the 'allow_port' helper function in .bashrc? (y/n): " install_helper
if [[ "$install_helper" =~ ^[Yy]$ ]]; then
    target_rcs=()
    [ -f "$HOME/.bashrc" ] && target_rcs+=("$HOME/.bashrc")
    [ -f "/root/.bashrc" ] && target_rcs+=("/root/.bashrc")
    if [ -n "$SUDO_USER" ] && [ -f "/home/$SUDO_USER/.bashrc" ]; then
        target_rcs+=("/home/$SUDO_USER/.bashrc")
    fi

    # Deduplicate target rc files
    unique_rcs=()
    for rc in "${target_rcs[@]}"; do
        if [[ ! " ${unique_rcs[*]} " =~ " ${rc} " ]]; then
            unique_rcs+=("$rc")
        fi
    done

    for rc in "${unique_rcs[@]}"; do
        # Clean up any previously installed allow_port function block
        sudo sed -i '/# === allow_port function start ===/,/# === allow_port function end ===/d' "$rc" 2>/dev/null || true
        cat << 'EOF' | sudo tee -a "$rc" > /dev/null

# === allow_port function start ===
allow_port() {
    if [ -z "$1" ]; then
        echo "Usage: allow_port <port|start:end> [tcp|udp|both]"
        echo "Examples:"
        echo "  allow_port 8080"
        echo "  allow_port 8080 tcp"
        echo "  allow_port 51820 udp"
        echo "  allow_port 3000:3005 tcp"
        echo "  allow_port 8000 both"
        return 1
    fi

    local port_input="$1"
    # Convert range separator '-' to ':' for iptables compatibility (e.g. 3000-3005 -> 3000:3005)
    local port="${port_input//-/:}"
    local proto_input="${2:-tcp}"
    proto_input=$(echo "$proto_input" | tr '[:upper:]' '[:lower:]')

    local protocols=()
    if [ "$proto_input" = "both" ] || [ "$proto_input" = "all" ] || [ "$proto_input" = "tcp/udp" ] || [ "$proto_input" = "udp/tcp" ]; then
        protocols=("tcp" "udp")
    elif [ "$proto_input" = "tcp" ] || [ "$proto_input" = "udp" ]; then
        protocols=("$proto_input")
    else
        echo "Invalid protocol: $proto_input. Use tcp, udp, or both."
        return 1
    fi

    for p in "${protocols[@]}"; do
        # IPv4 rule
        if ! sudo iptables -C INPUT -p "$p" --dport "$port" -j ACCEPT 2>/dev/null; then
            sudo iptables -A INPUT -p "$p" --dport "$port" -j ACCEPT
            echo "Added IPv4 iptables rule: ACCEPT $p port $port"
        else
            echo "IPv4 rule for $p port $port already exists."
        fi

        # IPv6 rule
        if command -v ip6tables >/dev/null 2>&1; then
            if ! sudo ip6tables -C INPUT -p "$p" --dport "$port" -j ACCEPT 2>/dev/null; then
                sudo ip6tables -A INPUT -p "$p" --dport "$port" -j ACCEPT
                echo "Added IPv6 ip6tables rule: ACCEPT $p port $port"
            else
                echo "IPv6 rule for $p port $port already exists."
            fi
        fi
    done

    # Save rules persistently
    sudo mkdir -p /etc/iptables
    sudo iptables-save | sudo tee /etc/iptables/rules.v4 > /dev/null
    if command -v ip6tables-save >/dev/null 2>&1; then
        sudo ip6tables-save | sudo tee /etc/iptables/rules.v6 > /dev/null
    fi
    if command -v netfilter-persistent >/dev/null 2>&1; then
        sudo netfilter-persistent save >/dev/null 2>&1 || true
    fi

    echo "Port(s) $port ($proto_input) successfully allowed and saved persistently."
}
alias open_port=allow_port
# === allow_port function end ===
EOF
        if [ -n "$SUDO_USER" ] && [ "$rc" = "/home/$SUDO_USER/.bashrc" ]; then
            sudo chown "$SUDO_USER:$SUDO_USER" "$rc" 2>/dev/null || true
        fi
        echo "Installed allow_port function to $rc"
    done

    echo -e "\nFunction 'allow_port' (and alias 'open_port') installed successfully!"
    echo -e "Usage examples:"
    echo -e "  allow_port 8080          # Allows TCP port 8080"
    echo -e "  allow_port 8080 tcp      # Allows TCP port 8080"
    echo -e "  allow_port 51820 udp     # Allows UDP port 51820"
    echo -e "  allow_port 3000:3005 tcp # Allows TCP port range 3000 to 3005"
    echo -e "  allow_port 8000 both     # Allows both TCP and UDP for port 8000"
    echo -e "\nNote: Run 'source ~/.bashrc' or start a new terminal session to use it immediately."
else
    echo "Skipping allow_port helper function installation."
fi

echo -e "\nSetup complete!"