#!/bin/bash

SDAGLUE_X86="https://repository.eu1.sdaconsole.io/glue/v2/linux/386/stable/sdaglue.zip"
SDAGLUE_AMD64="https://repository.eu1.sdaconsole.io/glue/v2/linux/amd64/stable/sdaglue.zip"
SDAGLUE_ARM="https://repository.eu1.sdaconsole.io/glue/v2/linux/arm/stable/sdaglue.zip"
SDAGLUE_ARM64="https://repository.eu1.sdaconsole.io/glue/v2/linux/arm64/stable/sdaglue.zip"
SE_CLIENT_X86="https://repository.eu1.sdaconsole.io/glue/lib/se_client-v4.44-linux-x86.tar.gz"
SE_CLIENT_AMD64="https://repository.eu1.sdaconsole.io/glue/lib/se_client-v4.44-linux-amd64.tar.gz"
SE_CLIENT_ARM="https://repository.eu1.sdaconsole.io/glue/lib/se_client-v4.44-linux-arm.tar.gz"
SE_CLIENT_ARM64="https://repository.eu1.sdaconsole.io/glue/lib/se_client-v4.44-linux-arm64.tar.gz"

# Constants
BIN_FILE="/usr/local/bin/sdaglue"
LIB_DIR="/usr/local/lib/sdaglue"
VAR_DIR="/var/lib/sdaglue"

set -euo pipefail
umask 022

# Defaults for optional behaviour (can be overridden via CLI flags)
SKIP_UPDATE=false
SKIP_COMMON_DEPS=false
SKIP_BUILD_DEPS=false
SKIP_OPENVPN=false

usage() {
    cat <<'EOF'
Usage: install.linux.v1.sh [options]

Options:
  --skip-update         Skip refreshing the package manager cache (update_cmd).
  --skip-common-deps    Skip installing common system dependencies (common_deps).
  --skip-build-deps     Skip installing build dependencies (build_deps).
  --skip-openvpn        Skip the OpenVPN check and installation prompt.
  -h, --help            Show this help message and exit.
EOF
}

while [ $# -gt 0 ]; do
    case "$1" in
    --skip-update)
        SKIP_UPDATE=true
        ;;
    --skip-common-deps)
        SKIP_COMMON_DEPS=true
        ;;
    --skip-build-deps)
        SKIP_BUILD_DEPS=true
        ;;
    --skip-openvpn)
        SKIP_OPENVPN=true
        ;;
    -h | --help)
        usage
        exit 0
        ;;
    *)
        echo "> Unknown option: $1"
        usage
        exit 1
        ;;
    esac
    shift
done

echo "###############################################################################"
echo "#                         SDA Glue v1 for Linux Gateways                      #"
echo "###############################################################################"
echo "# This script will automatically install the SDA Glue.                        #"
echo "# For more information about the SDA Glue, please visit:                      #"
echo "# https://docs.softwaredefinedautomation.io/app                               #"
echo "###############################################################################"

if [ "$EUID" -ne 0 ]; then
    echo "> This script requires sudo permissions."
    if ! sudo echo >/dev/null; then
        echo "> Unable to get sudo permissions. Exiting."
        exit 1
    fi
    sudo_cmd="sudo -E"
else
    sudo_cmd=""
fi

# Check for systemd
if ! pidof systemd >/dev/null; then
    echo "> This system does not appear to use systemd, which is required by SDA Glue."
    echo "> Please, contact the SDA Team for assistance."
    exit 1
fi

# Detect package manager and distribution
if command -v apt-get &>/dev/null; then
    pkg_mgr="apt-get"
    update_cmd="$sudo_cmd apt-get update"
    install_cmd="$sudo_cmd apt-get install -y"
    common_deps="iproute2 iputils-ping net-tools iptables netcat-traditional tcpdump nmap unzip"
    build_deps="build-essential gcc make zlib1g-dev libssl-dev libreadline-dev libncurses-dev"
    openvpn_pkg="openvpn"
elif command -v dnf &>/dev/null; then
    pkg_mgr="dnf"
    update_cmd="$sudo_cmd dnf makecache"
    install_cmd="$sudo_cmd dnf install -y"
    common_deps="iproute iputils net-tools iptables nmap nc tcpdump unzip"
    build_deps="gcc make glibc-devel zlib-devel openssl-devel readline-devel ncurses-devel"
    openvpn_pkg="openvpn"
elif command -v yum &>/dev/null; then
    pkg_mgr="yum"
    update_cmd="$sudo_cmd yum makecache"
    install_cmd="$sudo_cmd yum install -y"
    common_deps="iproute iputils net-tools iptables nmap nc tcpdump unzip"
    build_deps="gcc make glibc-devel zlib-devel openssl-devel readline-devel ncurses-devel"
    openvpn_pkg="openvpn"
elif command -v zypper &>/dev/null; then
    pkg_mgr="zypper"
    update_cmd="$sudo_cmd zypper refresh"
    install_cmd="$sudo_cmd zypper install -y"
    common_deps="iproute2 iputils net-tools iptables nmap netcat tcpdump unzip"
    build_deps="gcc make glibc-devel zlib-devel libopenssl-devel readline-devel ncurses-devel"
    openvpn_pkg="openvpn"
elif command -v pacman &>/dev/null; then
    pkg_mgr="pacman"
    update_cmd="$sudo_cmd pacman -Sy --noconfirm"
    install_cmd="$sudo_cmd pacman -S --noconfirm --needed"
    common_deps="iproute2 iputils net-tools iptables-nft nmap ncat tcpdump unzip"
    build_deps="base-devel zlib openssl readline ncurses"
    openvpn_pkg="openvpn"
else
    echo "> Unsupported Linux distribution."
    echo "> Supported package managers are: apt, dnf, yum, zypper."
    exit 1
fi

echo ""
echo "-------------------------------------------------------------------------------"
echo "> Detected package manager: $pkg_mgr"
if [ "$SKIP_UPDATE" = true ]; then
    echo "> Skipping package cache update (--skip-update)."
else
    echo "> Updating package cache..."
    echo "-------------------------------------------------------------------------------"
    eval "$update_cmd"
fi

echo ""
echo "-------------------------------------------------------------------------------"
if [ "$SKIP_COMMON_DEPS" = true ]; then
    echo "> Skipping system dependencies installation (--skip-common-deps)."
else
    echo "> Installing system dependencies..."
    echo "-------------------------------------------------------------------------------"
    eval "$install_cmd $common_deps"
fi

echo ""
echo "-------------------------------------------------------------------------------"
if [ "$SKIP_BUILD_DEPS" = true ]; then
    echo "> Skipping build dependencies installation (--skip-build-deps)."
else
    echo "> Installing build dependencies..."
    echo "-------------------------------------------------------------------------------"
    eval "$install_cmd $build_deps"
fi

echo ""
echo "> System dependencies installed successfully."

# OpenVPN is an optional runtime dependency used by the SSL Tunnel operation mode.
echo ""
echo "-------------------------------------------------------------------------------"
echo "> Checking for OpenVPN..."
echo "-------------------------------------------------------------------------------"
if [ "$SKIP_OPENVPN" = true ]; then
    echo "> Skipping OpenVPN check and installation (--skip-openvpn)."
elif command -v openvpn &>/dev/null; then
    echo "> OpenVPN is already installed."
else
    echo "> OpenVPN was not found on this system."
    echo "> OpenVPN may be required for the SSL Tunnel operation mode."
    install_openvpn=false
    if [ -e /dev/tty ]; then
        printf "> Would you like to pre-install OpenVPN now? (y/N) "
        read -r openvpn_answer </dev/tty || openvpn_answer=""
        case "$openvpn_answer" in
        [yY] | [yY][eE][sS])
            install_openvpn=true
            ;;
        esac
    else
        echo "> No interactive terminal detected; skipping OpenVPN installation."
        echo "> Re-run with OpenVPN installed, or install '$openvpn_pkg' manually if needed."
    fi

    if [ "$install_openvpn" = true ]; then
        echo "> Installing OpenVPN..."
        eval "$install_cmd $openvpn_pkg"
        echo "> OpenVPN installed successfully."
    else
        echo "> Continuing without OpenVPN. You can install '$openvpn_pkg' later if needed."
    fi
fi

if test -f $BIN_FILE && $BIN_FILE -v | grep -q "v0."; then
    echo "> Uninstalling old version of SDA Glue v0..."
    eval "$sudo_cmd $BIN_FILE service stop || true"
    eval "$sudo_cmd $BIN_FILE service uninstall || true"
    eval "$sudo_cmd rm -rf $BIN_FILE"
    eval "$sudo_cmd rm -rf $LIB_DIR"
    eval "$sudo_cmd rm -rf $VAR_DIR"
    echo "> SDA Glue v0 has been successfully uninstalled."
    echo "> You'll need to configure it again with 'sdaglue login' after installation."
fi

# Create a temporary working directory for staging downloaded files
STAGE_DIR="$(mktemp -d)"
# Create lib directory for modules
eval "$sudo_cmd mkdir -p $LIB_DIR"
# Ensure the temporary directory is deleted on script exit
cleanup() {
    echo "> Cleaning up..."
    eval "$sudo_cmd rm -rf $STAGE_DIR"
}
# Ensure cleaning up installation files on exit error
# Cleanup only on error
cleanup_on_error() {
    echo "> An error occurred. Cleaning up partial install..."
    eval "$sudo_cmd rm -rf $STAGE_DIR"
    eval "$sudo_cmd rm -f $BIN_FILE"
    eval "$sudo_cmd rm -rf $LIB_DIR"
}
# Trap signals to ensure cleanup on exit
trap cleanup EXIT
trap cleanup_on_error ERR
trap 'echo "> Installation interrupted."; cleanup; cleanup_on_error; exit 1' INT TERM

ARCH=$(uname -m)
BITS=$(getconf LONG_BIT)

case ${ARCH} in
# AMD/Intel 64‑bit
x86_64 | amd64)
    if [ "$BITS" = "32" ]; then
        PLATFORM=x86
        SE_CLIENT_URL=$SE_CLIENT_X86
        SDAGLUE_URL=$SDAGLUE_X86
    else
        PLATFORM=x86_64
        SE_CLIENT_URL=$SE_CLIENT_AMD64
        SDAGLUE_URL=$SDAGLUE_AMD64
    fi
    ;;

# Legacy x86 systems
i386 | i486 | i586 | i686)
    PLATFORM=x86
    SE_CLIENT_URL=$SE_CLIENT_X86
    SDAGLUE_URL=$SDAGLUE_X86
    ;;

# 64‑bit ARM   (A‑class CPUs, Apple M‑series, Pi 4/5 64‑bit OS, etc.)
aarch64* | arm64)
    PLATFORM=arm64
    SE_CLIENT_URL=$SE_CLIENT_ARM64
    SDAGLUE_URL=$SDAGLUE_ARM64
    ;;

# 32‑bit ARM   (Pi Zero/1/2/3 with 32‑bit OS, some embedded boards)
armv[4-7]*)
    PLATFORM=arm
    SE_CLIENT_URL=$SE_CLIENT_ARM
    SDAGLUE_URL=$SDAGLUE_ARM
    ;;
*)
    echo "> Unsupported architecture: $ARCH"
    echo "> Please contact the SDA Team for assistance."
    exit 1
    ;;
esac

echo "> Selecting installation for platform $PLATFORM"
echo ""
echo "> Downloading SDA Glue from $SDAGLUE_URL ..."
eval "$sudo_cmd curl -fsSL '$SDAGLUE_URL' -o $STAGE_DIR/sdaglue.zip" && CURL_STATUS=0 || CURL_STATUS=$?

if [ "$CURL_STATUS" != "0" ]; then
    if [ "$CURL_STATUS" = "22" ]; then
        # Try unstable if stable failed (HTTP error - code 22)
        ALT_SDAGLUE_URL="${SDAGLUE_URL/\/stable\//\/unstable\/}"
        echo "> Downloading SDA Glue from $ALT_SDAGLUE_URL ..."
        eval "$sudo_cmd curl -fsSL '$ALT_SDAGLUE_URL' -o $STAGE_DIR/sdaglue.zip"
        CURL_STATUS=$?
        if [ "$CURL_STATUS" != "0" ]; then
            echo "> Failed to download SDA Glue (curl exit code $CURL_STATUS)."
            exit 1
        fi
    else
        echo "> Failed to download SDA Glue (curl exit code $CURL_STATUS)."
        exit 1
    fi
fi

if test -f $LIB_DIR/sdaglue; then
    echo "> Stopping the existing SDA Glue Service..."
    eval "$sudo_cmd $LIB_DIR/sdaglue service stop &>/dev/null || true"
    eval "$sudo_cmd $LIB_DIR/sdaglue service uninstall &>/dev/null || true"
fi

eval "$sudo_cmd unzip -o $STAGE_DIR/sdaglue.zip -d $LIB_DIR"
eval "$sudo_cmd chmod +x $LIB_DIR/sdaglue"
eval "$sudo_cmd ln -sf $LIB_DIR/sdaglue $BIN_FILE"
echo ""
echo "> Downloading VPN Client from $SE_CLIENT_URL ..."
eval "$sudo_cmd curl -fsSL '$SE_CLIENT_URL' -o $STAGE_DIR/se_client.tar.gz"
echo ""
echo "> Bulding the VPN Client..."
eval "$sudo_cmd tar -xzf $STAGE_DIR/se_client.tar.gz -C $LIB_DIR"
eval "$sudo_cmd make -C $LIB_DIR/vpnclient"
echo ""
echo "> Installing the SDA Glue Service..."
eval "$sudo_cmd groupadd sdaglue &>/dev/null || true"
eval "$sudo_cmd usermod -aG sdaglue $USER &>/dev/null || true"

# If install reached here, we succeeded — disable cleanup traps
trap - ERR
trap - INT
trap - TERM

eval "$sudo_cmd $BIN_FILE service install"

echo "> Starting the SDA Glue Service..."
eval "$sudo_cmd $BIN_FILE service start"

echo "> Success! The SDA Glue v1 Service has been installed and started."
echo "> You may need to log out and back in to call 'sdaglue' without sudo."
echo "> Run 'sdaglue --help' for usage information."
