#!/usr/bin/env bash
set -e
if [[ $EUID -ne 0 ]]; then
   echo "This script must be run as root"
   exit 1
fi

OS_ID='unknown'
OS_VERSION_ID='unknown'
SUPPORTED='false'
INSTALL_COMPOSE='false'
INSTALL_DOCKER='false'
MIN_DOCKER_VERSION='28.5.2'
MIN_DOCKER_COMPOSE_VERSION='2.40.2'
SKIP_V4L2LOOPBACK=$1
SKIP_CUSTOM_RCLONE=$2
SKIP_EGRESS=$3
ROLE=$4
IGNORE_DEP_FAILURES=${5:-${IGNORE_DEP_FAILURES:-false}}
ENABLE_EPEL=${6:-}
SCRIPT_PATH="$( cd "$(dirname "$0")" ; pwd -P )"
V4L2LOOPBACK_VERSION='0.15.1'

CPU_ARCH="$(uname -m)"
ARCH=$(uname -m | sed 's/aarch64/arm64/g' | sed 's/x86_64/amd64/g')

function verlte() {
    [  "$1" = "`echo -e "$1\n$2" | sort -V | head -n1`" ]
}

# Checks if version $1 is less than $2
function verlt() {
    [ "$1" = "$2" ] && return 1 || verlte $1 $2
}

# All supported RHEL-family OSes (RHEL, Oracle, Rocky, Alma) use the linux/rhel/ Docker CE repo.
# The linux/centos/ path was frozen at 26.1.3 and is no longer used.
function docker_repo_url() {
    echo "https://download.docker.com/linux/rhel/docker-ce.repo"
}

function check_docker_dependencies (){
    echo "Checking if docker and docker compose are installed."
    set +e
    DOCKER_VERSION=$(docker system info | grep "Server Version" | awk '{ print $3 }')
    DOCKER="$(command -v docker)"
    DOCKER_COMPOSE="$(docker compose 2>/dev/null)"
    DOCKER_COMPOSE_VERSION="$( (docker compose version --short | sed s/v//g) 2>/dev/null)"
    set -e
    if [ -z "${DOCKER}" ] ; then
        INSTALL_DOCKER='true'
    else
        echo "Docker is installed"

        if [ -z "${DOCKER_VERSION}" ] ; then
            echo "Unable to check Docker version, is the Docker daemon running?"
            echo "Aborting Kasm Workspaces install."
            exit -1
        elif verlt "${DOCKER_VERSION}" "${MIN_DOCKER_VERSION}" ; then
            echo "The installed version of Docker is not supported; expected >=$MIN_DOCKER_VERSION but found $DOCKER_VERSION"
            echo "Aborting Kasm Workspaces install."
            exit -1
        else
            echo "$DOCKER_VERSION is a supported version of docker."
        fi
        
        
        if (docker system info | grep 'Docker Root Dir' | grep -q '/var/snap/docker') > /dev/null 2>&1 ; then
            echo "Detected version of Docker is installed via snap. This is unsupported."
            echo "Aborting Kasm Workspaces install."
            exit -1
        fi
    fi

    if [ -z "${DOCKER_COMPOSE}" ] ; then
        echo "Docker Compose is not installed."
        INSTALL_COMPOSE='true'
    else
        echo "Docker compose is installed"

        if [ -z "${DOCKER_COMPOSE_VERSION}" ] ; then
            echo "Unable to determine docker compose version"
            echo "Aborting workspaces install"
            exit -1
        elif verlt "${DOCKER_COMPOSE_VERSION}" "${MIN_DOCKER_COMPOSE_VERSION}" ; then
            echo "${DOCKER_COMPOSE_VERSION} is an old version of docker compose, installing a new version"
            INSTALL_COMPOSE='true'
        else
            echo "${DOCKER_COMPOSE_VERSION} is a supported version of docker compose"
        fi
    fi

    if [ "${INSTALL_DOCKER}" == 'false' ] && [ "${INSTALL_COMPOSE}" == 'false' ] ; then
        echo "Commands docker and docker compose detected, skipping Docker installation."
        # Set SUPPORTED=true so the script continues past the OS detection block below.
        # Previously this path did `exit 0` here, but we still need to run rclone/wireguard
        # installation for agent/all roles even when Docker is already present.
        SUPPORTED='true'
    fi
}

function install_docker_compose (){
   echo "Installing Docker Compose"
   mkdir -p /usr/local/lib/docker/cli-plugins
   curl -L https://github.com/docker/compose/releases/download/v2.40.2/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/lib/docker/cli-plugins/docker-compose
   chmod +x /usr/local/lib/docker/cli-plugins/docker-compose
}

function install_ubuntu (){
    echo "Ubuntu 20.04/22.04/24.04 Install"
    echo "Installing Base Ubuntu Packages"
    apt-get update
    apt-get install -y \
        apt-transport-https \
        ca-certificates \
        curl \
        netcat-openbsd \
        software-properties-common

    if dpkg -s docker-ce | grep Status: | grep installed ; then
      echo "Docker Installed"
    else
      echo "Installing Docker-CE"

      install -m 0755 -d /etc/apt/keyrings
      curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
      chmod a+r /etc/apt/keyrings/docker.asc
      echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" > /etc/apt/sources.list.d/docker.list
      apt-get update
      apt-get -y install docker-ce
    fi
}

function install_debian (){
    export LC_ALL=C LANG=C
    echo "Debian 11.x/12.x/13.x Install"
    echo "Installing Base Debian Packages"
    apt-get update
    apt-get install -y \
         ca-certificates \
         curl \
         locales \
         netcat-openbsd
    unset LC_ALL LANG
    sed -i -e 's/# *\(en_US\.UTF-8\)/\1/' /etc/locale.gen
    grep -q "^en_US.UTF-8 UTF-8" /etc/locale.gen || echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen
    locale-gen en_US.UTF-8
    echo "LANG=en_US.UTF-8" > /etc/default/locale
    export LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8

    if dpkg -s docker-ce | grep Status: | grep installed ; then
      echo "Docker Installed"
    else
      echo "Installing Docker-CE"

      install -m 0755 -d /etc/apt/keyrings
      curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
      chmod a+r /etc/apt/keyrings/docker.asc
      DOCKER_DEBIAN_CODENAME=$(. /etc/os-release && echo "${VERSION_CODENAME:-}")
      if [ -z "${DOCKER_DEBIAN_CODENAME}" ]; then
          echo "Unable to determine Debian codename from /etc/os-release"
          echo "Aborting Kasm Workspaces install."
          exit 1
      fi
      if ! curl -fsI --max-time 10 \
          "https://download.docker.com/linux/debian/dists/${DOCKER_DEBIAN_CODENAME}/Release" \
          >/dev/null 2>&1; then
          echo "Docker repo has no suite for ${DOCKER_DEBIAN_CODENAME}, falling back to bookworm"
          DOCKER_DEBIAN_CODENAME="bookworm"
      fi
      cat > /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/debian
Suites: ${DOCKER_DEBIAN_CODENAME}
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF
      apt-get update
      apt-get -y install docker-ce
    fi
}

function install_oracle (){
    echo "RHEL/Oracle/Rocky/Alma Linux 8.x/9.x Install"
    echo "Installing Base Packages"

    NO_BEST=""
    if [[ "${1}" == '"8.'* ]] || [[ "${1}" == '"9.'* ]]; then
        NO_BEST="--nobest"
    fi

    yum install -y yum-utils \
        device-mapper-persistent-data \
        lvm2 \
        lsof \
        nc

    yum-config-manager --add-repo "$(docker_repo_url)"

    echo "Installing Docker-CE"
    yum install -y docker-ce $NO_BEST
    systemctl start docker
}

function install_openssl (){
    if [ "${OS_ID}" == "ubuntu" ] && ( [ "${OS_VERSION_ID}" == '"20.04"' ] || [ "${OS_VERSION_ID}" == '"22.04"' ] || [ "${OS_VERSION_ID}" == '"24.04"' ] ) ; then
        apt-get update
        apt-get install -y openssl
    fi
    if [ "${OS_ID}" == "debian" ] && ( [ "${OS_VERSION_ID}" == '"11"' ] || [ "${OS_VERSION_ID}" == '"12"' ] || [ "${OS_VERSION_ID}" == '"13"' ] ) ; then
        apt-get update
        apt-get install -y openssl
    fi
    if [ "${OS_ID}" == '"ol"' ] && ( [[ "${OS_VERSION_ID}" == '"8.'* ]] || [[ "${OS_VERSION_ID}" == '"9.'* ]] ) ; then
        yum install -y openssl
    fi
    if [ "${OS_ID}" == '"rocky"' ] && ( [[ "${OS_VERSION_ID}" == '"8.'* ]] || [[ "${OS_VERSION_ID}" == '"9.'* ]] ) ; then
        dnf install -y openssl
    fi
    if [ "${OS_ID}" == '"almalinux"' ] && ( [[ "${OS_VERSION_ID}" == '"8.'* ]] || [[ "${OS_VERSION_ID}" == '"9.'* ]] ) ; then
        dnf install -y openssl
    fi
    if [ "${OS_ID}" == '"rhel"' ] && ( [[ "${OS_VERSION_ID}" == '"8.'* ]] || [[ "${OS_VERSION_ID}" == '"9.'* ]] ) ; then
        yum install -y openssl
    fi
}

function dep_failure_prompt() {
    local dep_name="${1}"
    printf "\n\n"
    echo "####### Failed to install ${dep_name} #######"
    echo "# Kasm Workspaces may have reduced functionality without this dependency. #"
    printf "\n"
    if [ "${IGNORE_DEP_FAILURES}" == "true" ]; then
        echo "# Ignoring failed dependency (--ignore-dep-failures is set). Continuing installation. #"
        printf "\n"
        return 0
    fi
    if [ ! -t 0 ] || [ ! -r /dev/tty ]; then
        echo "# Non-interactive mode detected. Re-run with --ignore-dep-failures to skip optional dependencies. #"
        printf "\n"
        exit 1
    fi
    while true; do
        read -p "Would you like to continue with the installation (y/n)? " choice </dev/tty
        case "$choice" in
          y|Y )
            echo "Continuing installation"
            return 0
            ;;
          n|N )
            echo "Installation cannot continue"
            exit 1
            ;;
          * )
            echo "Invalid response. Please enter y or n."
            ;;
        esac
    done
}

function prompt_install_epel() {
    local pkg="${1}"
    if [ "${ENABLE_EPEL}" == "true" ]; then
        return 0
    fi
    if [ ! -t 0 ] || [ ! -r /dev/tty ]; then
        return 1
    fi
    printf "\n\n"
    echo "####### EPEL Repository Required #######"
    echo "# '${pkg}' is not available in the currently configured repositories."
    echo "# EPEL (Extra Packages for Enterprise Linux) is a community repo maintained"
    echo "# by the Fedora Project that provides this package for RHEL-based systems."
    echo "# Re-run with --skip-egress to skip wireguard and bypass this prompt."
    printf "\n"
    while true; do
        read -p "Would you like to enable EPEL to install ${pkg} (y/n)? " choice </dev/tty
        case "${choice}" in
            y|Y) return 0 ;;
            n|N) return 1 ;;
            *) echo "Invalid response. Please enter y or n." ;;
        esac
    done
}

# Install EPEL on RHEL/Rocky/Alma/Oracle 8 or 9. Tries the distro repo first,
# then falls back to the Fedora Project URL (needed for unregistered RHEL EC2 AMIs).
function install_epel_repo() {
    local major="$1"   # 8 or 9
    if dnf install -y epel-release 2>/dev/null; then
        return 0
    fi
    dnf install -y "https://dl.fedoraproject.org/pub/epel/epel-release-latest-${major}.noarch.rpm"
}

# Install the wireguard kernel module on RHEL 8.
# RHEL 8's kernel-modules-extra does NOT contain wireguard.ko (unlike RHEL 9).
# Use ELRepo's kmod-wireguard, which provides a prebuilt module signed against
# the RHEL 8 kABI. Falls back to wireguard-dkms if the kmod doesn't load.
function install_wireguard_kmod_el8() {
    echo "Installing wireguard kernel module via ELRepo (kmod-wireguard)..."
    if ! rpm -q elrepo-release >/dev/null 2>&1; then
        dnf install -y https://www.elrepo.org/elrepo-release-8.el8.elrepo.noarch.rpm || return 1
    fi
    if dnf install -y kmod-wireguard; then
        depmod -a
        if modprobe wireguard >/dev/null 2>&1; then
            return 0
        fi
        echo "kmod-wireguard installed but module did not load; trying DKMS fallback..."
    fi
    # DKMS fallback: build module against running kernel
    dnf install -y dkms wireguard-tools "kernel-devel-$(uname -r)" "kernel-headers-$(uname -r)" || return 1
    if dnf list --available wireguard-dkms >/dev/null 2>&1; then
        dnf install -y wireguard-dkms || return 1
    fi
    depmod -a
    modprobe wireguard >/dev/null 2>&1
}


function install_v4l2loopback (){
    if ( ( [ "${OS_ID}" == "ubuntu" ] && ( [ "${OS_VERSION_ID}" == '"20.04"' ] || [ "${OS_VERSION_ID}" == '"22.04"' ] || [ "${OS_VERSION_ID}" == '"24.04"' ] ) ) || \
         ( [ "${OS_ID}" == "debian" ] && ( [ "${OS_VERSION_ID}" == '"11"' ] || [ "${OS_VERSION_ID}" == '"12"' ] || [ "${OS_VERSION_ID}" == '"13"' ] ) ) ) && \
       [ "${SKIP_V4L2LOOPBACK}" == "false" ] ; then
        if [ -f /.dockerenv ] ; then
            echo "Skipping v4l2loopback install: running inside a Docker container."
        elif [ -d /var/lib/dkms/v4l2loopback ] ; then
            echo "Skipping v4l2loopback install: already installed (found /var/lib/dkms/v4l2loopback)."
        else
            # Debian 11/12/13 uses cloud kernels that don't expose videodev via modprobe,
            # but DKMS install works without it — skip the modprobe gate for those.
            # Kernel headers must be installed first for DKMS to build the module.
            SKIP_VIDEODEV_CHECK="false"
            if [ "${OS_ID}" == "debian" ] && ( [ "${OS_VERSION_ID}" == '"11"' ] || [ "${OS_VERSION_ID}" == '"12"' ] || [ "${OS_VERSION_ID}" == '"13"' ] ); then
                SKIP_VIDEODEV_CHECK="true"
                apt-get update
                apt-get install -y linux-headers-$(uname -r) || echo "WARN: Could not install linux-headers-$(uname -r), v4l2loopback DKMS build may fail."
            fi

            modprobe videodev > /dev/null 2>&1 || :
            if [ "${SKIP_VIDEODEV_CHECK}" == "true" ] || ( [ -f /proc/modules ] && grep -q videodev /proc/modules ); then
                if dpkg -s v4l2loopback-dkms >/dev/null 2>&1; then
                    if dpkg --compare-versions "$(dpkg-query -W -f='${Version}' v4l2loopback-dkms)" lt "${V4L2LOOPBACK_VERSION}"; then
                        echo "v4l2loopback needs to be upgraded"
                        apt remove -y v4l2loopback-dkms
                    fi
                fi
                OSVID=$(echo ${OS_VERSION_ID} | sed 's/"//g')
                V4L2_DEB="/tmp/${OS_ID}_${OSVID}-v4l2loopback-dkms.deb"
                V4L2_URL="https://kasmweb-build-artifacts.s3.amazonaws.com/v4l2loopback-ubuntu/${V4L2LOOPBACK_VERSION}/${OS_ID}_${OSVID}-v4l2loopback-dkms.deb"
                V4L2_SKIPPED="false"
                set +e
                apt-get update
                
                if curl -fL -o "${V4L2_DEB}" "${V4L2_URL}" && dpkg-deb --info "${V4L2_DEB}" >/dev/null 2>&1; then
                    apt install -y "${V4L2_DEB}"
                    V4L2_RESULT=$?
                else
                    echo "WARN: v4l2loopback DKMS package for ${OS_ID}_${OSVID} (v${V4L2LOOPBACK_VERSION}) is unavailable or invalid; skipping webcam support."
                    V4L2_RESULT=1
                    V4L2_SKIPPED="true"
                fi
                set -e
                rm -f "${V4L2_DEB}"
                if [ ${V4L2_RESULT} -eq 0 ]; then
                    ${SCRIPT_PATH}/bin/utils/yq_$(uname -m) -i '(.group_settings.[] | select(.name=="allow_kasm_webcam" and .group_id=="68d557ac-4cac-42cc-a9f3-1c7c853de0f3")) .value = "True"' ${SCRIPT_PATH}/conf/database/seed_data/default_properties.yaml
                elif [ "${V4L2_SKIPPED}" != "true" ]; then
                    dep_failure_prompt "v4l2loopback (webcam support)"
                fi
            else
                dep_failure_prompt "v4l2loopback (webcam support): videodev module not available in kernel"
            fi
        fi
    fi
}

if [ -f /etc/os-release ] ; then
    OS_ID="$(awk -F= '/^ID=/{print $2}' /etc/os-release)"
    OS_VERSION_ID="$(awk -F= '/^VERSION_ID/{print $2}' /etc/os-release)"
fi

if ! openssl version > /dev/null 2>&1; then
    echo "Installing OpenSSL"
    install_openssl
    if ! openssl version > /dev/null 2>&1; then
        echo "Failed to install openssl. Aborting Kasm Workspaces install."
        exit 1
    fi
fi

function install_lsof (){
    if [ "${OS_ID}" == "ubuntu" ] && ( [ "${OS_VERSION_ID}" == '"20.04"' ] || [ "${OS_VERSION_ID}" == '"22.04"' ] || [ "${OS_VERSION_ID}" == '"24.04"' ] ) ; then
        apt-get update
        apt-get install -y lsof
    fi
    if [ "${OS_ID}" == "debian" ] && ( [ "${OS_VERSION_ID}" == '"11"' ] || [ "${OS_VERSION_ID}" == '"12"' ] || [ "${OS_VERSION_ID}" == '"13"' ] ) ; then
        apt-get update
        apt-get install -y lsof
    fi
    if [ "${OS_ID}" == '"ol"' ] && ( [[ "${OS_VERSION_ID}" == '"8.'* ]] || [[ "${OS_VERSION_ID}" == '"9.'* ]] ) ; then
        yum install -y lsof
    fi
    if [ "${OS_ID}" == '"rocky"' ] && ( [[ "${OS_VERSION_ID}" == '"8.'* ]] || [[ "${OS_VERSION_ID}" == '"9.'* ]] ) ; then
        dnf install -y lsof
    fi
    if [ "${OS_ID}" == '"almalinux"' ] && ( [[ "${OS_VERSION_ID}" == '"8.'* ]] || [[ "${OS_VERSION_ID}" == '"9.'* ]] ) ; then
        dnf install -y lsof
    fi
    if [ "${OS_ID}" == '"rhel"' ] && ( [[ "${OS_VERSION_ID}" == '"8.'* ]] || [[ "${OS_VERSION_ID}" == '"9.'* ]] ) ; then
        yum install -y lsof
    fi
}

function install_rclone_plugin () {
    if ! fusermount --version > /dev/null 2>&1 && ! fusermount3 --version > /dev/null 2>&1; then
        set +e
        if [ "${OS_ID}" == "ubuntu" ] && [ "${OS_VERSION_ID}" == '"20.04"' ]; then
            apt-get update
            apt-get install -y fuse
        elif [ "${OS_ID}" == "ubuntu" ] && ( [ "${OS_VERSION_ID}" == '"22.04"' ] || [ "${OS_VERSION_ID}" == '"24.04"' ] ); then
            apt-get update
            apt-get install -y fuse3
        elif [ "${OS_ID}" == "debian" ] && [ "${OS_VERSION_ID}" == '"11"' ]; then
            apt-get update
            apt-get install -y fuse
        elif [ "${OS_ID}" == "debian" ] && ( [ "${OS_VERSION_ID}" == '"12"' ] || [ "${OS_VERSION_ID}" == '"13"' ] ); then
            apt-get update
            apt-get install -y fuse3
        elif ( [ "${OS_ID}" == '"ol"' ] || [ "${OS_ID}" == '"rhel"' ] || [ "${OS_ID}" == '"rocky"' ] || [ "${OS_ID}" == '"almalinux"' ] ) && ( [[ "${OS_VERSION_ID}" == '"8.'* ]] || [[ "${OS_VERSION_ID}" == '"9.'* ]] ); then
            yum install -y fuse3
        fi
        set -e
        if ! fusermount --version > /dev/null 2>&1 && ! fusermount3 --version > /dev/null 2>&1; then
            dep_failure_prompt "fuse (required for rclone persistent storage)"
        fi
    fi
    DOCKER_PLUGIN_DIR=$(docker info | awk -F': ' '/Docker Root Dir/ {print $2}')-plugins
    if [ ! -d ${DOCKER_PLUGIN_DIR}/rclone ]; then
        echo "installing rclone docker plugin"
        mkdir -p ${DOCKER_PLUGIN_DIR}/rclone/config
        mkdir -p ${DOCKER_PLUGIN_DIR}/rclone/cache
        set +e
        docker plugin install rclone/docker-volume-rclone:${ARCH} args="-v" --alias rclone --grant-all-permissions
        RCLONE_RESULT=$?
        set -e
        if [ ${RCLONE_RESULT} -ne 0 ]; then
            dep_failure_prompt "rclone docker volume plugin (persistent storage support)"
        else
            if [ "${SKIP_CUSTOM_RCLONE}" == "false" ] ; then
                rm -f ${DOCKER_PLUGIN_DIR}/rclone/cache/docker-plugin.state
                ln -s /dev/null ${DOCKER_PLUGIN_DIR}/rclone/cache/docker-plugin.state
            fi
        fi
    fi
}

function install_wireguard_kernel_module() {
    WIRE_FAIL="false"
    if [ "${OS_ID}" == "ubuntu" ] && ( [ "${OS_VERSION_ID}" == '"20.04"' ] || [ "${OS_VERSION_ID}" == '"22.04"' ] || [ "${OS_VERSION_ID}" == '"24.04"' ] ) ; then
        if ! modprobe wireguard > /dev/null 2>&1; then
            $(apt-get update && apt-get install -y wireguard && modprobe wireguard) || WIRE_FAIL="true"
        fi

        # ensure loading on reboot
        if ! grep -q wireguard /etc/modules && [ "${WIRE_FAIL}" == "false" ]; then
            echo "wireguard" >> /etc/modules
        fi
    fi
    
    if [ "${OS_ID}" == "debian" ] && ( [ "${OS_VERSION_ID}" == '"11"' ] || [ "${OS_VERSION_ID}" == '"12"' ] || [ "${OS_VERSION_ID}" == '"13"' ] ) ; then
        if ! modprobe wireguard > /dev/null 2>&1; then
            $(apt-get update && apt-get install -y wireguard) || WIRE_FAIL="true"
        fi
    fi

    if [ "${OS_ID}" == '"ol"' ] && [[ "${OS_VERSION_ID}" == '"9.'* ]] ; then
        if ! modprobe wireguard > /dev/null 2>&1; then
            yum install -y wireguard-tools || WIRE_FAIL="true"
        fi
    fi

    # --- el8 RHEL-family (RHEL 8 / Rocky 8 / Alma 8 / Oracle 8) ---
    # Userspace tools come from EPEL. Kernel module is NOT in kernel-modules-extra
    # on RHEL 8 (only on RHEL 9), so use ELRepo's kmod-wireguard.
    if ( [ "${OS_ID}" == '"rhel"' ] || [ "${OS_ID}" == '"rocky"' ] || [ "${OS_ID}" == '"almalinux"' ] || [ "${OS_ID}" == '"ol"' ] ) \
       && [[ "${OS_VERSION_ID}" == '"8.'* ]] ; then
        if [ "${CPU_ARCH}" == "aarch64" ]; then
            echo "WARN: WireGuard kernel module is not available as a prebuilt package for el8 aarch64."
            echo "      ELRepo's kmod-wireguard is x86_64 only; kernel-modules-extra does not include"
            echo "      wireguard.ko on RHEL/Rocky/Alma/Oracle 8 aarch64. Egress (WireGuard) will not be available."
            echo "      To enable it, install wireguard-dkms from EPEL after ensuring kernel-devel is present."
            echo "      Note: RHEL/Rocky/Alma/Oracle 9 aarch64 ships wireguard in the stock kernel and does not"
            echo "      have this limitation."
            WIRE_FAIL="skip"
        elif ! modprobe wireguard > /dev/null 2>&1; then
            # Step 1: userspace wireguard-tools (EPEL).
            if ! rpm -q wireguard-tools >/dev/null 2>&1; then
                if dnf list --available wireguard-tools >/dev/null 2>&1; then
                    dnf install -y wireguard-tools || WIRE_FAIL="true"
                elif prompt_install_epel "wireguard-tools"; then
                    if install_epel_repo 8; then
                        dnf install -y wireguard-tools || WIRE_FAIL="true"
                    else
                        WIRE_FAIL="true"
                    fi
                else
                    echo "Skipping wireguard-tools: not available in configured repos and EPEL not enabled."
                    WIRE_FAIL="true"
                fi
            fi
            # Step 2: kernel module via ELRepo (with DKMS fallback).
            if [ "${WIRE_FAIL}" == "false" ] && ! modprobe wireguard >/dev/null 2>&1; then
                if install_wireguard_kmod_el8; then
                    : # success
                else
                    echo "WARN: failed to install wireguard kernel module from ELRepo."
                    WIRE_FAIL="true"
                fi
            fi
            # Final check; module may need a reboot to load even when installed.
            if [ "${WIRE_FAIL}" == "false" ] && ! modprobe wireguard >/dev/null 2>&1; then
                echo "WARN: wireguard kernel module installed but could not be loaded. A reboot may be required."
                WIRE_FAIL="skip"
            fi
        fi
    fi

    if [ "${OS_ID}" == '"rocky"' ] && [[ "${OS_VERSION_ID}" == '"9.'* ]] ; then
        if ! modprobe wireguard > /dev/null 2>&1; then
            dnf install -y wireguard-tools || WIRE_FAIL="true"
        fi
    fi

    if [ "${OS_ID}" == '"almalinux"' ] && [[ "${OS_VERSION_ID}" == '"9.'* ]] ; then
        if ! modprobe wireguard > /dev/null 2>&1; then
            dnf install -y wireguard-tools || WIRE_FAIL="true"
        fi
    fi

    if [ "${OS_ID}" == '"rhel"' ] && [[ "${OS_VERSION_ID}" == '"9.'* ]] ; then
        if ! modprobe wireguard > /dev/null 2>&1; then
            yum install -y wireguard-tools || WIRE_FAIL="true"
        fi
    fi
    if [ "${WIRE_FAIL}" == "false" ] && ! modprobe wireguard > /dev/null 2>&1; then
        WIRE_FAIL="true"
    fi
    if [ "${WIRE_FAIL}" == "true" ]; then
        dep_failure_prompt "Wireguard (egress support)"
    fi
}

if ! lsof -v > /dev/null 2>&1; then
    echo "Installing lsof"
    install_lsof
    if ! lsof -v > /dev/null 2>&1; then
        echo "Failed to install lsof. Aborting Kasm Workspaces install."
        exit 1
    fi
fi

install_v4l2loopback
check_docker_dependencies

if [ "${OS_ID}" == "ubuntu" ] && ( [ "${OS_VERSION_ID}" == '"20.04"' ] || [ "${OS_VERSION_ID}" == '"22.04"' ] || [ "${OS_VERSION_ID}" == '"24.04"' ] ) ; then
    SUPPORTED='true'
    if [ $INSTALL_DOCKER == 'true' ] ; then
        install_ubuntu
    fi

    if [ $INSTALL_COMPOSE == 'true' ] ; then
        install_docker_compose
    fi
fi

if [ "${OS_ID}" == "debian" ] && ( [ "${OS_VERSION_ID}" == '"11"' ] || [ "${OS_VERSION_ID}" == '"12"' ] || [ "${OS_VERSION_ID}" == '"13"' ] ) ; then
    SUPPORTED='true'
    if [ $INSTALL_DOCKER == 'true' ] ; then
        install_debian
    fi

    if [ $INSTALL_COMPOSE == 'true' ] ; then
        install_docker_compose
    fi
fi

if [ "${OS_ID}" == '"ol"' ] && ( [[ "${OS_VERSION_ID}" == '"8.'* ]] || [[ "${OS_VERSION_ID}" == '"9.'* ]] ) ; then
    SUPPORTED='true'
    if [ $INSTALL_DOCKER == 'true' ] ; then
        install_oracle ${OS_VERSION_ID}
    fi

    if [ $INSTALL_COMPOSE == 'true' ] ; then
        install_docker_compose
    fi
fi

if [ "${OS_ID}" == '"rocky"' ] && ( [[ "${OS_VERSION_ID}" == '"8.'* ]] || [[ "${OS_VERSION_ID}" == '"9.'* ]] ) ; then
    SUPPORTED='true'
    if [ $INSTALL_DOCKER == 'true' ] ; then
        install_oracle ${OS_VERSION_ID}
    fi

    if [ $INSTALL_COMPOSE == 'true' ] ; then
        install_docker_compose
    fi
fi

if [ "${OS_ID}" == '"almalinux"' ] && ( [[ "${OS_VERSION_ID}" == '"8.'* ]] || [[ "${OS_VERSION_ID}" == '"9.'* ]] ) ; then
    SUPPORTED='true'
    if [ $INSTALL_DOCKER == 'true' ] ; then
        install_oracle ${OS_VERSION_ID}
    fi

    if [ $INSTALL_COMPOSE == 'true' ] ; then
        install_docker_compose
    fi
fi

if [ "${OS_ID}" == '"rhel"' ] && ( [[ "${OS_VERSION_ID}" == '"8.'* ]] || [[ "${OS_VERSION_ID}" == '"9.'* ]] ) ; then
    SUPPORTED='true'
    if [ $INSTALL_DOCKER == 'true' ] ; then
        install_oracle ${OS_VERSION_ID}
    fi

    if [ $INSTALL_COMPOSE == 'true' ] ; then
        install_docker_compose
    fi
fi

if [ "${SUPPORTED}" == "false" ] ; then
   echo "Installation Not Supported for this Operating System. Exiting"
   exit -1
fi

if [ "${ROLE}" == "all" ] || [ "${ROLE}" == "agent" ]; then
  install_rclone_plugin
  if [ "${SKIP_EGRESS}" == "false" ] ; then
    install_wireguard_kernel_module
  fi
fi

echo "Dependency Installation Complete"
