#!/bin/bash

# _get_architecture()
# _get_distribution()
# _isRunning()
# _isInstalled()
# _isVarPhi()
# bck_file
# clean_oldest_file()
# download_template()
# install_package()
# mount_bindfs()
# mount_cifs()
# mount_nfs()
# search_and_replace()

TS_IP=$(tailscale ip -4)
TS_HOSTNAME=$(hostname).swallow-grue.ts.net

_get_architecture() {

if [[ $1 == "--help" || $1 == "-h" || $1 == "-?" ]]
then
    echo "Returns the architecture of the computer"
    echo "Usage: No param"
    exit 0
fi
ARCHI=""
case $(uname -m) in
    i386 | i686)   	ARCHI="386" ;;
    x86_64) 		ARCHI="amd64" ;;
    arm | aarch64)    		dpkg --print-architecture | grep -q "arm64" && ARCHI="arm64" || ARCHI="arm" ;;
	armv7l)			ARCHI="old_arm" ;;
	*)   			echo "Unable to determine system architecture."; exit 1 ;;
esac
# option 2
# dpkg --print-architecture
}

_get_distribution() {
	DISTRIBUTION_NAME=$(dpkg --status tzdata|grep Provides|cut -f2 -d'-')
}

_get_latest_version() {
  local REPO_NAME=$1
  curl https://api.github.com/repos/"$REPO_NAME"/releases/latest | grep tag_name | cut -d ':' -f 2 | xargs
}

_isContainerRunning() {
# Name of the container to check
  CONTAINER_NAME=$1

  # Check if the Docker daemon is running and accessible.
  if ! [ -x "$(command -v docker)" ]; then
    echo "Docker not installed or not running. Please start Docker."
    exit 1
  fi

  # Check if a container name was provided
  if [ -z "$CONTAINER_NAME" ]; then
    echo "Usage: $0 <container_name>"
    exit 1
  fi

  # Check if the container is running
  STATUS=$(docker inspect -f '{{.State.Running}}' "$CONTAINER_NAME" 2>/dev/null)

  if [ "$STATUS" == "true" ]; then
    echo "Container '$CONTAINER_NAME' is up and running."
    return 0
  elif [ "$STATUS" == "false" ]; then
    echo "Container '$CONTAINER_NAME' exists but is not running."
    return 1
  else
    echo "Container '$CONTAINER_NAME' does not exist."
    return 2
  fi
}

_isInstalled() {
  local MY_APP=$1
  if ! hash "$MY_APP" >/dev/null 2>&1 ; then
    if ! dpkg -l "$MY_APP" >/dev/null 2>&1 ; then
      if ! [[ $(systemctl list-units --all -t service --full --no-legend "$MY_APP.service" | sed 's/^\s*//g' | cut -f1 -d' ') == $MY_APP.service ]]; then
        if ! _isRunning "$MY_APP" ; then
          return 1
        else
          return 0
        fi
      else
        return 0
      fi
    else
      return 0
    fi
  else
    return 0
  fi

}

_isMounted() {
  if $(mount |awk '{print $3}'| grep -w "$1") != '' ; then
    return 0
  else 
    return 1
  fi
}


_isx86 () {
  case $(uname -m) in
    'i386'|'i686'|'x86_64') exit 0 ;;
    *) exit 1  ;;
esac
}

# Function to detect Raspberry Pi
is_raspberry_pi() {
    if grep -q "Raspberry Pi" /proc/device-tree/model 2>/dev/null; then
        return 0
    elif grep -q "BCM" /proc/cpuinfo 2>/dev/null; then
        return 0
    else
        return 1
    fi
}

_isRunning() {
  local MY_APP=$1
  if pgrep -fl "$MY_APP" >/dev/nul 2>&1; then
    return 0
  else
    return 1
  fi
}
## example 1: checking if "gedit" is running
# if _isRunning gedit; then
#     echo "gedit is running"
# else
#     echo "gedit is not running"
# fi
## example 2: start lxpanel if it is not there
# if ! _isRunning lxpanel; then
#     lxpanel &
# fi
## or
# _isRunning lxpanel || (lxpanel &)

_isServiceRunning() {
  MY_SVC=$1
  case $(sudo systemctl show -p SubState --value "$MY_SVC") in
    running)
      return 0
      ;;
    dead) 
      return 1
      ;;
    *)
      return 2
      ;;
  esac
}
_isStringInFile() {
  local SEARCHED_STRING=$1
  local SEARCHED_FILE=$2
  case $(grep -Fx "$SEARCHED_STRING" "$SEARCHED_FILE" >/dev/null; echo $?) in
    0)
      return 0
      ;;
    1)
      return 1
      ;;
    *)
      return 2
      ;;
  esac
}

_isVarEmpty() {
  local MY_VAR=$1
  #local MY_VAR_IF_EMPTY=$2
  if [[ -z "$MY_VAR" ]]; then
    #if [[ -z "$MY_VAR" ]]; then
    #fi
    return 0
  else
    return 1
  fi
}

_isVarUnset() {
  local MY_VAR=$1
  #local MY_VAR_IF_EMPTY=$2
  if [[ -z "$MY_VAR" ]]; then
    #if [[ -z "$MY_VAR" ]]; then
    #fi
    return 0
  else
    return 1
  fi
}

_isVarPhi() {
  local MY_VAR=$1
  if [[ -z $MY_VAR && ${MY_VAR+x} ]]; then
    return 0
  else
    return 1
  fi
}

_isVirt() {
  grep -q ^flags.*\ hypervisor\  /proc/cpuinfo >/dev/null 2>&1
  return
}

appinst () {
  APP=$1
  sudo apt update
  type -p "$APP" >/dev/null || sudo apt install -y "$APP"
}
bck_file () { 
  sudo mv "$1"{,.backup_"$(date +%Y%m%d_%H%M)"}; 
}

bck_list_pbs () {
  export PBS_PASSWORD_FILE=/root/.pbs_password
  export PBS_FINGERPRINT="be:e1:16:01:34:26:e7:27:a5:c0:ef:d5:54:27:02:38:ea:94:6d:fc:d1:6e:c5:b2:ec:7d:c3:d9:d5:32:9e:c0"
  export PBS_REPOSITORY=bck_ops@pbs@localhost:vmx-pbs_data1
  apt clean cache
 
  MY_GROUP=$1
  proxmox-backup-client snapshot list "$MY_GROUP"
  unset PBS_PASSWORD_FILE
}

bck_pbs_change_owner () {
  export PBS_PASSWORD_FILE=/root/.pbs_password
  export PBS_FINGERPRINT="be:e1:16:01:34:26:e7:27:a5:c0:ef:d5:54:27:02:38:ea:94:6d:fc:d1:6e:c5:b2:ec:7d:c3:d9:d5:32:9e:c0"
  export PBS_REPOSITORY=bck_ops@pbs@localhost:vmx-pbs_data1
  NEW_OWNER=bck_ops@pbs
  CLIENT_LIST=$(proxmox-backup-client list | cut -c5- | grep -E '(ct|vm|host)/.*' | cut -d' ' -f1)

  # Boucle sur la liste
  for MYCLIENT in $CLIENT_LIST; do
    echo "My Client : $MYCLIENT"
    proxmox-backup-client change-owner "$MYCLIENT" "$NEW_OWNER"
  done
  unset PBS_PASSWORD_FILE
}

clean_oldest_file() {
  # Print usage if requested.
  if [[ $1 == "--help" || $1 == "-h" || $1 == "-?" ]]
  then
      echo "Deletes the $1 oldest files from $2 dir"
      echo "Usage: $0 [files limit] $1 [dir] $2 [filename]"
      exit 0
  fi
  # The script receives the limit as an argument.
  limit=$1
  dir=$2
  filename=$3
  number_of_files=$(ls $dir/$filename* | wc -l)

  if [ "$number_of_files" -gt "$limit" ]
  then
      # There are more files than the limit
      # So we need to remove the older ones.
      cd $dir
      ls -t | tail --lines=+$(expr $limit + 1) | xargs -d '\n' rm
  fi
}

desbreit_server2server() {
  SRC_FILE=bck2pbs.sh
  SRC_PATH=/myshares/scripts/$SRC_FILE
  DST_PATH=/opt/scripts_local/$SRC_FILE
  SSH_HOST=""
  ! [ "$HOSTNAME" = "vmx-nas" ] && SSH_HOST="root@ket.inxs.me:" 
  sudo rsync -avP -e "ssh -o StrictHostKeyChecking=no" "$SSH_HOST/$SRC_PATH" "$DST_PATH" && chmod +x $DST_PATH
  /bin/bash $DST_PATH
}
download_template() {
  local TEMPLATE="$1"
  local DEST="$2"
  shift 2
  local OPTIONS=("$@")

  local HOSTNAME
  HOSTNAME=$(hostname)

  local DRY_RUN=false
  local FORCE=false
  local SHOW_HELP=false
  local RSYNC_EXTRA=()

  # ─── Parse Options ───
  for opt in "${OPTIONS[@]}"; do
    case "$opt" in
      --dry-run) DRY_RUN=true ;;
      --force) FORCE=true ;;
      --help) SHOW_HELP=true ;;
      --include=*|--exclude=*) RSYNC_EXTRA+=("$opt") ;;
      *)
        echo "❌ Unknown option: $opt"
        return 1
        ;;
    esac
  done

  # ─── Help ───
  if [[ "$SHOW_HELP" == true || -z "$TEMPLATE" || -z "$DEST" ]]; then
    echo "📘 Usage: download_template <source> <destination> [options]"
    echo "Options:"
    echo "  --dry-run        Show what would be copied without executing"
    echo "  --force          Overwrite even if destination exists"
    echo "  --include=PATTERN  Include files matching pattern (rsync)"
    echo "  --exclude=PATTERN  Exclude files matching pattern (rsync)"
    echo "  --help           Show this help"
    return 0
  fi

  # ─── Dereference Symlink Source (if local) ───
  if [[ "$HOSTNAME" == "vmx-nas" && -L "$TEMPLATE" ]]; then
    TEMPLATE=$(readlink -f "$TEMPLATE")
  fi

  # ─── Glob Check (local only) ───
  if [[ "$TEMPLATE" == *'*'* && "$HOSTNAME" == "vmx-nas" ]]; then
    if ! compgen -G "$TEMPLATE" > /dev/null; then
      echo "⚠️ No files match pattern: $TEMPLATE"
      return 0
    fi
  fi

  # ─── Build rsync command ───
  local RSYNC_OPTS="-avP --copy-links"  # copy target of symlink
  [[ "$DRY_RUN" == true ]] && RSYNC_OPTS+=" --dry-run"

  for rule in "${RSYNC_EXTRA[@]}"; do
    RSYNC_OPTS+=" $rule"
  done

  local SOURCE_PATH="$TEMPLATE"
  if [[ "$HOSTNAME" != "vmx-nas" ]]; then
    SOURCE_PATH="dbi@ket.inxs.me:$TEMPLATE"
    RSYNC_OPTS+=' -e "ssh -o StrictHostKeyChecking=no"'
  fi

  # ─── Directory Detection ───
  if [[ "$TEMPLATE" == *'*'* || "$TEMPLATE" == */ || -d "$TEMPLATE" ]]; then
    mkdir -p "$DEST"
  else
    mkdir -p "$(dirname "$DEST")"
    if [[ -f "$DEST" && "$FORCE" != true ]]; then
      echo "✅ $DEST already exists — skipping (use --force to overwrite)"
      return 0
    fi
  fi

  # ─── Log Action ───
  if [[ "$DRY_RUN" == true ]]; then
    echo "🧪 [Dry-run] Would rsync: $SOURCE_PATH → $DEST"
  else
    echo "📥 Rsync: $SOURCE_PATH → $DEST"
  fi

  # ─── Execute Rsync ───
  eval sudo rsync $RSYNC_OPTS "$SOURCE_PATH" "$DEST"
  local EXIT_CODE=$?

  if [[ $EXIT_CODE -ne 0 ]]; then
    echo "❌ Rsync failed for $TEMPLATE"
    return 1
  fi

  echo "✅ Downloaded successfully: $TEMPLATE → $DEST"
}
escape_spec_char() {
	# (rev | sed -e 's/|/`/' | rev) --> reverse the string and replace the 1st / (last / before rev) with nothing then rev again
	# (sed -e 's/\///') --> replace the 1st / with nothing
	# (-e 's/\//\-/g') --> replace the following / with _
	# -e ()'s/\./\_/g') --> replace the . with _
	echo "$1" | rev | sed -e 's/|/`/' | rev | sed -e 's/\///' -e 's/\//\-/g' -e 's/\./\_/g'
}
escapify() { 
# https://stackoverflow.com/questions/56810226/add-escapes-to-special-characters-in-a-string-as-a-function
# use sed in a pipeline to add escapes before any of a list of characters, specified as a bracket expression
  echo "$1" | sed 's/[][ \~`!@#$%^&*()=+{}|;:'"'"'",<>/?-]/\\&/g'; 
}
file_exists() {
  MYFILE=$1
  if [ -f "$MYFILE" ]; then
    return 0
  else
    return 1
  fi
}

hc_update() {
  local HEALTHCHECK_KEY=$1
  local RETURN_CODE=$2
  HC_URL=https://hc.noxs.me/ping/$HEALTHCHECK_KEY/$RETURN_CODE
  if [[ "$(which curl)" ]]; then 
    curl -m 10 --retry 5 "$HC_URL" -o /dev/null 2>&1
  else 
    wget --spider --tries=5 --no-verbose --no-check-certificate "$HC_URL"
  fi
}

install_package() {
  local MY_PACKAGE=$1
  shift
  local MY_PACKAGE_FULLPATH="/myshares/scripts/setup/$MY_PACKAGE"
  local DST_PATH="/tmp/$MY_PACKAGE"
  
  echo "Downloading package $MY_PACKAGE..."
  sudo rsync -avP -e "ssh -o StrictHostKeyChecking=no" dbi@ket.inxs.me:"$MY_PACKAGE_FULLPATH" "$DST_PATH"
  sudo chmod +x "$DST_PATH"
  
  echo "Installing package $MY_PACKAGE..."
  bash "$DST_PATH" "$@"
}

log() { 
  # ------  Log to stdout --------
  printf '[%s] %s\n' "$(date +%F\ %T) - $(hostname)"  "$*"; 
  
  # ------ Log to systemd logger --------
  # Default tag = name of the script that called this function.
  #
  #  • ${BASH_SOURCE[1]} → the file where the *caller* lives  
  #    (works even if that file was sourced)  
  #  • if that’s empty (e.g. interactive shell), fall back to $0
  #
  local tag="${LOG_TAG:-$(basename "${BASH_SOURCE[1]:-$0}")}"
  local pri="user.notice"

  # Optional: allow `log -p facility.severity "msg"`
  if [[ $1 == -p* ]]; then
      pri=${1#-p }
      shift
  fi


#  systemd-cat -t "$tag" -p "$pri" -- "$*"
#  systemd-cat -t "$tag" -- "$*"

logger -t "$tag" -p "$pri" -- "$*"

}

mergerfs_tools() {
  TOOL_SELECTED=$1
  DIR=$2
  case "$TOOL_SELECTED" in
    fsck)
      mergerfs.fsck -v -f nonroot "$DIR"
      ;;
    balance) 
      # Will move files from the most filled drive (percentage wise) to the least filled drive
      mergerfs.balance "$DIR"
      ;;
    consolidate)
      # Consolidate files in a single mergerfs directory onto a single drive, recursively.
      mergerfs.consolidate "$DIR"
      ;;
    *)
      return 2
      ;;
  esac

}
mount_cifs() {
  local MNT_CIFS=$1
  local SRV_CIFS=$2
  local OPTION_CIFS=nobrl,username=smb_user,password=Name-Splinter3-Struggle-Sponsor-Peroxide-Matador,uid=dbi,gid=3333,dir_mode=0775,file_mode=0775
  # local OPTION_CIFS=credentials=/etc/.smb_credentials,uid=2222,gid=2222,dir_mode=0755,file_mode=0755
  local MOUNTPOINT_CIFS="/mnt/$SRV_CIFS/$MNT_CIFS"
  download_template /myshares/shared/etc/.smb_credentials /etc/.smb_credentials
  mkdir -p "$MOUNTPOINT_CIFS"
  unmount "$MOUNTPOINT_CIFS"
  #echo "mount -t cifs -o $OPTION_CIFS //$SRV_CIFS.swallow-grue.ts.net/$MNT_CIFS $MOUNTPOINT_CIFS"
  mount -t cifs -o "$OPTION_CIFS" "//$SRV_CIFS.swallow-grue.ts.net/$MNT_CIFS" "$MOUNTPOINT_CIFS"
}

mount_bindfs() {
   SRV_BFS=$1
   MNT_BFS=$2
   USER_BFS=dbi
   GROUP_BFS=users
   PERM_BFS=0777
   if [ "$SRV_BFS" == "kom" ]; then
      MOUNTPOINT_BFS="/data/$SRV_BFS/$MNT_BFS"
      ROOT_BFS="/mnt/$SRV_BFS/$MNT_BFS"
      USER_BFS=backup
      GROUP_BFS=backup
      PERM_BFS=0775
   elif [ "$SRV_BFS" == "kyt" ]; then
      MOUNTPOINT_BFS="/data/$SRV_BFS"
      ROOT_BFS="/mnt/$SRV_BFS/media"
   elif [ "$SRV_BFS" == "kut-download" ]; then
      MOUNTPOINT_BFS="/data/$SRV_BFS"
      ROOT_BFS="/mnt/$SRV_BFS/move"
   elif [ "$SRV_BFS" == "vmx-nas" ]; then
      MOUNTPOINT_BFS="/data/$SRV_BFS"
      ROOT_BFS="/mnt/$SRV_BFS"
   fi
   mkdir -p "$MOUNTPOINT_BFS"
   unmount "$MOUNTPOINT_BFS"
   bindfs --force-user="$USER_BFS" --force-group="$GROUP_BFS" --perms="$PERM_BFS" "$ROOT_BFS" "$MOUNTPOINT_BFS"
}

mount_nfs() {
   local SRV_NFS=$1
   local MNT_NFS=$2
   local ROOT_NFS=$3
   local OPTION_NFS=rsize=4096,wsize=4096,rw,nfsvers=3
   local MOUNTPOINT_NFS="/mnt/$SRV_NFS/$MNT_NFS"
   mkdir -p "$MOUNTPOINT_NFS"
   unmount "$MOUNTPOINT_NFS"
   mount -t nfs -o "$OPTION_NFS" "$SRV_NFS.swallow-grue.ts.net:/$ROOT_NFS/$MNT_NFS" "$MOUNTPOINT_NFS"
}

log_msg() {
  local level="$1"        # INFO, ERROR, WARN, etc.
  local message="$2"
  local script_name="${BASH_SOURCE[1]##*/}"
  local hostname="$(hostname -s)"
  local timestamp="$(date '+%Y-%m-%d %H:%M:%S')"
  local log_file="/var/log/scripts.log"

  # Si le fichier n'existe pas, le créer et appliquer les droits
  if [[ ! -f "$log_file" ]]; then
    touch "$log_file" 2>/dev/null
    chown root:adm "$log_file" 2>/dev/null
    chmod 664 "$log_file" 2>/dev/null
  fi

  # Ajoute la ligne de log
  echo "[$timestamp] [$hostname] [$script_name] [$level] $message" >> "$log_file"

  # En option : log dans syslog aussi
  # logger -t "$script_name" "[$level] $message"
}

notify_apprise() {
  local apprise_env_file="/root/.apprise.env"
  local title="$1"
  local message="$2"
  local label="$3"
  local apprise_url=""

  if ! command -v apprise &>/dev/null; then
    log_msg "ERROR" "apprise-cli non installé"
    return 1
  fi

  if [[ ! -f "$apprise_env_file" ]]; then
    log_msg "ERROR" "Fichier $apprise_env_file introuvable"
    return 1
  fi

  if [[ -n "$label" ]]; then
    apprise_url=$(grep -E "^$label\|" "$apprise_env_file" | head -n1 | cut -d'|' -f2-)
    if [[ -z "$apprise_url" ]]; then
      log_msg "ERROR" "Aucune URL trouvée pour le label '$label'"
      return 1
    fi
  else
    apprise_url=$(head -n1 "$apprise_env_file" | cut -d'|' -f2-)
    if [[ -z "$apprise_url" ]]; then
      log_msg "ERROR" "Aucune URL trouvée en première ligne de $apprise_env_file"
      return 1
    fi
  fi

  apprise -t "$title" -b "$message" "$apprise_url" >/dev/null 2>&1
  if [[ $? -eq 0 ]]; then
    log_msg "INFO" "Notification envoyée via Apprise${label:+ (label: $label)}"
    return 0
  else
    log_msg "ERROR" "Échec de l'envoi de la notification via Apprise"
    return 1
  fi
}

log_and_notify() {
  local level="$1"     # INFO, WARN, ERROR, etc.
  local title="$2"
  local message="$3"
  local label="$4"     # facultatif

  log_msg "$level" "$message"
  notify_apprise "$title" "$message" "$label"
}

param_handle() {
  # Standard routine to handle cli parameters
  # u --> -u --> username, a --> -a --> age, f --> -f --> fullname
  while getopts u:a:f: flag
  do
    case "${flag}" in
        u) username=${OPTARG};;
        a) age=${OPTARG};;
        f) fullname=${OPTARG};;
        *) echo "Error: No or wrong parameter provided. \n The scripts expects -u -a -f params." && exit 1
    esac
  done
  echo "Username: $username";
  echo "Age: $age";
  echo "Full Name: $fullname";
}

path_basename() {
  # Returns the filename with or without extension
  # Expl: path_basename "/root/test/denis.txt" --> denis.txt
  # Expl: path_basename "/root/test/denis.txt" ".txt" --> denis
  # Expl: path_basename "/root/test" --> test
  PATH_BASENAME=$(basename "$1" "$2")
}
path_dirname() {
  # Returns the dirs of a provided path by removing the last part after /
  # Expl: path_dirname "/root/test/" --> /root
  # Expl: path_dirnname "/root/test/denis.txt" --> /root/test
  PATH_DIRNAME=$(dirname "$1")
}
path_rootdir() {
  # Returns the parent oot dir of a provided path
  # Expl: path_rootdir "/root/test/denis/" --> /root
  PATH_ROOTDIR="/$(echo "$1" | cut -d "/" -f 2)"
}
path_resolve() {
  # Resolve a complex dir even with ~ and .. dir=~/Library/../Desktop/../..
  # builtin command use the builtin (original) command in case of alias mod 
  local ORIGNAL=$1
  PATH_RESOLVE=$(builtin cd "$ORIGINAL"; pwd)
}
path_slash_trim() {
  # Removes multiple trailing slashes /root/test/// --> /root/test
  local ORIGINAL=$1
  PATH_SLASH_TRIM=$(echo "$ORIGINAL" | sed 's:/*$::')
}
process_check() {
  [ "$1" = "" ]  && return 0
  PID=$(pgrep -n -i -f "$1")
  MY_PID=$PID
  [ "$PID" = "" ] && return 1  || return 0
}
process_kill() {
  MY_PROC=$1
  WAIT_SECONDS=$2
  [ "$2" = "" ]  &&  WAIT_SECONDS=10
  # Getting the PID of the process
  process_check "$MY_PROC"
  # Number of seconds to wait before using "kill -9"
  # Counter to keep count of how many seconds have passed
  count=0
  while kill "$MY_PID" > /dev/null
  do
      # Wait for one second
      sleep 1
      # Increment the second counter
      ((count++))
      # Has the process been killed? If so, exit the loop.
      if ! ps -p "$MY_PID" > /dev/null ; then
          break
      fi
      # Have we exceeded $WAIT_SECONDS? If so, kill the process with "kill -9"
      # and exit the loop
      if [ $count -gt "$WAIT_SECONDS" ]; then
          kill -9 "$MY_PID"
          break
      fi
  done
  echo "Process has been killed after $count seconds."
}

require_root() {
  if [[ $EUID -ne 0 ]]; then
    echo "❌ please run as root (sudo …)" >&2
    exit 1
  fi
}

search_and_replace() {
  local MY_SEARCH=$1
  local MY_REPLACE=$2
  local MY_FILE=$3
  sudo sed -i "s|$MY_SEARCH|$MY_REPLACE|g" "$MY_FILE"
}

# ──────────────────────────────────────────────
# 📤 Send test email via msmtp
# Parameters:
#   --from    Custom sender (default: <user>@<host>.inxs.be)
#   --to      Recipient email (default: $TO_ADDR or fallback to admin@inxs.be)
#   --subject Subject line (default: "Test from <hostname>")
#   --body    Email body (default: "MSMTP configured successfully on <hostname>")
#   --debug   Enable msmtp debug output and log email to /tmp/msmtp_test_email.txt
#   --help    Show this help message and exit
# ──────────────────────────────────────────────
send_test_mail() {
  local from="${USER}@$(hostname -s).inxs.be"
  local to="${TO_ADDR:-me@noxs.me}"
  local subject="Test from $(hostname)"
  local body="MSMTP configured successfully on $(hostname)"
  local debug=false

  if [[ "$1" == "--help" ]]; then
    echo "📤 Usage: send_test_mail [options]"
    echo ""
    echo "Options:"
    echo "  --from <email>     Sender address (default: ${USER}@<host>.inxs.be)"
    echo "  --to <email>       Recipient address (default: \$TO_ADDR or me@noxs.me)"
    echo "  --subject <text>   Subject line (default: \"Test from <hostname>\")"
    echo "  --body <text>      Email body (default: \"MSMTP configured successfully on <hostname>\")"
    echo "  --debug            Enable msmtp debug output and save message to /tmp/msmtp_test_email.txt"
    echo "  --help             Show this help message and exit"
    return 0
  fi

  # Parse named arguments
  while [[ $# -gt 0 ]]; do
    case "$1" in
      --from)    from="$2"; shift 2 ;;
      --to)      to="$2"; shift 2 ;;
      --subject) subject="$2"; shift 2 ;;
      --body)    body="$2"; shift 2 ;;
      --debug)   debug=true; shift ;;
      *)         echo "❌ Unknown parameter: $1. Use --help for usage."; return 1 ;;
    esac
  done

  echo "📤 Preparing test email..."
  echo "📨 From: $from"
  echo "📩 To: $to"
  echo "📝 Subject: $subject"

  if ! command -v msmtp >/dev/null 2>&1; then
    echo "❌ msmtp command not found. Cannot send test email."
    return 1
  fi

  local message="From: $from
To: $to
Subject: $subject

$body
"

  if $debug; then
    echo "$message" | tee /tmp/msmtp_test_email.txt | msmtp --debug --from="$from" "$to"
  else
    echo "$message" | msmtp --from="$from" "$to"
  fi

  if [[ $? -eq 0 ]]; then
    echo "✅ Test email successfully sent to $to."
  else
    echo "❌ Failed to send test email via msmtp."
    return 1
  fi
}

setup_marker() {
  # Code lines to be added to the top of each script that uses this function:
  # FORCE=false
  # for arg in "$@"; do
  #   [[ "$arg" == "--force" ]] && FORCE=true
  # done
  local action="${1:-}"
  local marker_name="${2:-}"
  local force="${3:-false}"
  local marker_dir="/etc/setup-markers"
  local marker_path="$marker_dir/$marker_name"

  case "$action" in
    check)
      if [[ -f "$marker_path" ]]; then
        echo "✅ Marker \"$marker_name\" found at $marker_path"
        [[ "$force" != "true" ]] && exit 0
      else
        echo "ℹ️ Marker \"$marker_name\" not found — continuing."
      fi
      ;;
    read)
      # Alias for 'check' with user-friendly output
      setup_marker check "$marker_name" "$force"
      ;;
    create)
      sudo mkdir -p "$marker_dir"
      sudo touch "$marker_path"
      echo "📍 Marker \"$marker_name\" created at $marker_path"
      ;;
    delete)
      if [[ -f "$marker_path" ]]; then
        sudo rm -f "$marker_path"
        echo "🗑 Marker \"$marker_name\" deleted from $marker_path"
      else
        echo "⚠️ Marker \"$marker_name\" not found — nothing to delete."
      fi
      ;;
    list)
      echo "📜 Setup markers in $marker_dir:"
      ls -1 "$marker_dir"
      ;;
    *)
      echo "❌ Invalid action: $action"
      echo "Usage:"
      echo "  setup_marker check  <marker_name> [true|false (force)]"
      echo "  setup_marker read   <marker_name> (alias for check)"
      echo "  setup_marker create <marker_name>"
      echo "  setup_marker delete <marker_name>"
      echo "  setup_marker list"
      return 1
      ;;
  esac
}

sudo_check() {
  [[ $EUID != 0 ]] && sudo ls /root >/dev/null 2>&1
}

unmount() {
  local MY_MNT=$1
  [[ $(mount |awk '{print $3}'| grep -w "$MY_MNT") != '' ]]  && fusermount -uz "$MY_MNT"
  umount "$MY_MNT" >/dev/nul 2>&1
}

# function version_compare () {
#   function sub_ver () {
#     local len=${#1}
#     temp=${1%%"."*} && indexOf=`echo ${1%%"."*} | echo ${#temp}`
#     echo -e "${1:0:indexOf}"
#   }
#   function cut_dot () {
#     local offset=${#1}
#     local length=${#2}
#     echo -e "${2:((++offset)):length}"
#   }
#   if [ -z "$1" ] || [ -z "$2" ]; then
#     echo "=" && exit 0
#   fi
#   local v1=`echo -e "${1}" | tr -d '[[:space:]]'`
#   local v2=`echo -e "${2}" | tr -d '[[:space:]]'`
#   local v1_sub=`sub_ver $v1`
#   local v2_sub=`sub_ver $v2`
#   if (( v1_sub > v2_sub )); then
#     echo ">"
#   elif (( v1_sub < v2_sub )); then
#     echo "<"
#   else
#     version_compare `cut_dot $v1_sub $v1` `cut_dot $v2_sub $v2`
#   fi
# }

# Compares to strings containing version numbers and returns < = > according to result
# version_compare `gcc --version` "5.0.0" --> return 0 if equal or greater
# https://unix.stackexchange.com/questions/285924/how-to-compare-a-programs-version-in-a-shell-script
version_compare()
{
  var1=$1;
  var2=$2;
  for i in 1 2 3
  do
    part1=$(echo $var1 | cut -d "." -f $i)
    part2=$(echo $var2 | cut -d "." -f $i)
    if [ $part1 -lt $part2 ]
    then
      return 0
    fi
  done
  return 1
}
