#!/bin/bash
set -euo pipefail

CONFIG_FILE="/opt/scripts_local/mount_delayed_table.conf"
LOG_FILE="/var/log/mount_network.log"
exec > >(tee -a "$LOG_FILE") 2>&1

FORCE_UNMOUNT_MODE="none"
FORCE_UNMOUNT_FILTER="all"

print_help() {
  echo "Usage: $0 [options]"
  echo
  echo "Options:"
  echo "  --force-unmount=defined        Unmount only mounts defined in config file"
  echo "  --force-unmount=all            Unmount all cifs, nfs, and bindfs mounts on the system"
  echo "  --force-unmount=only:<type>    Unmount only mounts of given type (cifs, nfs, bindfs) from system"
  echo "  -h, --help                     Show this help message"
  exit 0
}

while [[ $# -gt 0 ]]; do
  case "$1" in
    --force-unmount=only:*)
      FORCE_UNMOUNT_MODE="only"
      FORCE_UNMOUNT_FILTER="${1#only:}"
      shift
      ;;
    --force-unmount=*)
      FORCE_UNMOUNT_MODE="${1#*=}"
      shift
      ;;
    -f|--force-unmount)
      FORCE_UNMOUNT_MODE="defined"
      shift
      ;;
    -h|--help)
      print_help
      ;;
    *)
      echo "Unknown option: $1" >&2
      print_help
      ;;
  esac
done

if [[ "$EUID" -ne 0 ]]; then
  echo "❌ This script must be run as root. Please use sudo."
  exit 1
fi

[[ -f /etc/apprise.env ]] && source /etc/apprise.env

notify() {
  local message="$1"
  local host="$(hostname)"
  [[ -n "${APPRISE_URL:-}" ]] && apprise -b "[$host] $message" "$APPRISE_URL"
}

trim() {
  echo "$1" | xargs
}

retry() {
  local retries=3 delay=5 cmd="$1" label="$2"
  for attempt in $(seq 1 "$retries"); do
    echo "Attempt $attempt: $label"
    if eval "$cmd"; then return 0; fi
    echo "❌ $label failed (attempt $attempt)"
    sleep "$delay"
  done
  notify "❌ $label failed after $retries attempts"
  return 1
}

is_mounted() {
  local path="$1"
  mountpoint -q "$path" || grep -q " $(realpath "$path") " /proc/mounts
}

UPDATED=0
install_if_missing() {
  local pkg="$1"
  if ! dpkg -s "$pkg" &>/dev/null; then
    if [[ "$pkg" == "apprise" ]]; then
      echo "📦 'apprise' not found via apt — trying pip install"
      if ! command -v pip3 &>/dev/null; then
        echo "Installing pip..."
        apt-get install -y python3-pip
      fi
      pip3 install --quiet apprise
      return
    fi

    if [[ "$UPDATED" -eq 0 ]]; then
      echo "Running apt-get update..."
      apt-get update
      UPDATED=1
    fi

    echo "Installing: $pkg"
    apt-get install -y "$pkg"
  else
    echo "✓ Package '$pkg' is already installed"
  fi
}

for pkg in bindfs virt-what jq tailscale cifs-utils apprise nfs-common; do
  install_if_missing "$pkg"
done

IN_LXC=0
if virt-what | grep -q '^lxc$'; then
  echo "LXC container detected — CIFS mounts will be skipped."
  IN_LXC=1
fi

TIMEOUT=60; elapsed=0
while ! tailscale status --peers=false --json=true 2>/dev/null | jq -r '.Self.Online' | grep -q true; do
  echo "Waiting for Tailscale..."
  sleep 2
  ((elapsed += 2))
  if ((elapsed >= TIMEOUT)); then
    notify "❌ Tailscale not online after $TIMEOUT seconds. Aborting."
    exit 1
  fi
done

chmod +rx /mnt

CIFS_Mount() {
  local SERVER="$1" SHARE="$2" DEST="$3" PRESENTED_UID="$4" PRESENTED_GID="$5" MODE="$6"
  local CRED_FILE="/etc/.smb_credentials"
  [[ -f "$CRED_FILE" ]] || { notify "❌ Missing credentials: $CRED_FILE"; return 1; }
  is_mounted "$DEST" && { echo "Already mounted: $DEST"; return 0; }
  mkdir -p "$DEST"
  [[ -z "$MODE" || "$MODE" == "-" ]] && MODE="0770"

  if grep -q 'Raspberry Pi' /proc/device-tree/model 2>/dev/null; then
    echo "🐧 Raspberry Pi detected — using vers=2.1 for CIFS"
    OPTIONS="vers=2.1,credentials=$CRED_FILE,uid=$PRESENTED_UID,gid=$PRESENTED_GID,file_mode=$MODE,dir_mode=$MODE"
  else
    OPTIONS="vers=3.0,iocharset=utf8,noatime,nofail,credentials=$CRED_FILE,uid=$PRESENTED_UID,gid=$PRESENTED_GID,file_mode=$MODE,dir_mode=$MODE"
  fi

  echo "🔧 Mount options: $OPTIONS"
  retry "mount -t cifs \"//$SERVER/$SHARE\" \"$DEST\" -o \"$OPTIONS\"" "Mount //$SERVER/$SHARE"
}

NFS_Mount() {
  local SERVER="$1" SHARE="$2" DEST="$3" OPTIONS="$4"
  is_mounted "$DEST" && { echo "Already NFS-mounted: $DEST"; return 0; }
  mkdir -p "$DEST"
  [[ -z "$OPTIONS" || "$OPTIONS" == "-" ]] && OPTIONS="defaults,noatime,nofail"
  local REMOTE="${SERVER}:${SHARE}"
  echo "Mounting NFS share $REMOTE → $DEST with options: $OPTIONS"
  retry "mount -t nfs -o \"$OPTIONS\" \"$REMOTE\" \"$DEST\"" "NFS mount $REMOTE"
}

BINDFS_Mount() {
  local SRC="$1" DST="$2" PRESENTED_UID="$3" PRESENTED_GID="$4" PRESENTED_PERMS="$5" APPLIED_USER="$6" APPLIED_FILE_PERMS="$7"
  [[ -z "$DST" ]] && { echo "⚠️ Empty destination — skipping"; return 1; }
  local WAIT_TIMEOUT=60 WAIT_INTERVAL=1 waited=0
  while [[ ! -d "$SRC" ]]; do
    if (( waited >= WAIT_TIMEOUT )); then
      notify "❌ Timeout waiting for source dir: $SRC"
      return 1
    fi
    echo "⏳ Waiting for $SRC to exist..."
    sleep "$WAIT_INTERVAL"
    (( waited += WAIT_INTERVAL ))
  done
  is_mounted "$DST" && { echo "Already bind-mounted: $DST"; return 0; }
  mkdir -p "$DST"
  umount "$DST" >/dev/null 2>&1 || true
  [[ -z "$PRESENTED_UID" || "$PRESENTED_UID" == "-" ]] && PRESENTED_UID="root"
  [[ -z "$PRESENTED_GID" || "$PRESENTED_GID" == "-" ]] && PRESENTED_GID="root"
  [[ -z "$APPLIED_USER" || "$APPLIED_USER" == "-" ]] && APPLIED_USER="$PRESENTED_UID"
  local OPTIONS="--force-user=$PRESENTED_UID --force-group=$PRESENTED_GID --create-for-user=$APPLIED_USER --create-for-group=$APPLIED_USER --chown-ignore --chgrp-ignore"
  [[ "$PRESENTED_PERMS" != "-" && -n "$PRESENTED_PERMS" ]] && OPTIONS+=" --perms=$PRESENTED_PERMS"
  if [[ "$APPLIED_FILE_PERMS" =~ ^[0-7]{3,4}$ ]]; then
    OPTIONS+=" --create-with-perms=$APPLIED_FILE_PERMS"
  elif [[ "$APPLIED_FILE_PERMS" != "-" && -n "$APPLIED_FILE_PERMS" ]]; then
    echo "⚠️ Skipping invalid --create-with-perms (must be numeric): $APPLIED_FILE_PERMS"
  fi
  echo "🔗 Bind mounting $SRC → $DST (presented as user=$PRESENTED_UID, group=$PRESENTED_GID, creates as $APPLIED_USER)"
  retry "bindfs $OPTIONS \"$SRC\" \"$DST\"" "Bind mount $SRC → $DST"
}

[[ -f "$CONFIG_FILE" ]] || { notify "❌ Missing config: $CONFIG_FILE"; exit 1; }

parse_config_line() {
  IFS='|' read -r raw1 raw2 raw3 raw4 raw5 raw6 raw7 raw8 raw9 raw10 <<< "$1"
  echo "$(trim "$raw1")|$(trim "$raw2")|$(trim "$raw3")|$(trim "$raw4")|$(trim "$raw5")|$(trim "$raw6")|$(trim "$raw7")|$(trim "$raw8")|$(trim "$raw9")|$(trim "$raw10")"
}

if [[ "$FORCE_UNMOUNT_MODE" == "defined" ]]; then
  echo "Unmounting mounts defined in config..."
  while IFS= read -r line; do
    [[ "$line" =~ ^#.*$ || -z "$line" ]] && continue
    parsed="$(parse_config_line "$line")"
    [[ $(awk -F'|' '{print NF}' <<< "$parsed") -ne 10 ]] && { echo "⚠️ Malformed line, skipping: $line"; continue; }
    IFS='|' read -r SERVER _ DEST TYPE _ <<< "$parsed"
    if is_mounted "$DEST"; then
      echo "Unmounting $DEST..."
      umount -l "$DEST" || echo "⚠️ Could not unmount $DEST"
    fi
  done < "$CONFIG_FILE"
  echo "All config-defined mounts have been unmounted."
elif [[ "$FORCE_UNMOUNT_MODE" == "all" ]]; then
  echo "Unmounting all CIFS, NFS, and bindfs mounts on the system..."
  mount | awk '/type (cifs|nfs|fuse.bindfs)/ { print $3 }' | while read -r mountpoint; do
    echo "Unmounting $mountpoint..."
    umount -l "$mountpoint" || echo "⚠️ Could not unmount $mountpoint"
  done
  echo "All relevant system-wide mounts have been unmounted."
elif [[ "$FORCE_UNMOUNT_MODE" == "only" ]]; then
  echo "Unmounting only mounts of type: $FORCE_UNMOUNT_FILTER"
  case "$FORCE_UNMOUNT_FILTER" in
    cifs|nfs|bindfs)
      grep_pattern="type $FORCE_UNMOUNT_FILTER"
      [[ "$FORCE_UNMOUNT_FILTER" == "bindfs" ]] && grep_pattern="fuse.bindfs"
      mount | awk -v pat="$grep_pattern" '$0 ~ pat { print $3 }' | while read -r mountpoint; do
        echo "Unmounting $mountpoint..."
        umount -l "$mountpoint" || echo "⚠️ Could not unmount $mountpoint"
      done
      echo "Unmounting complete for type: $FORCE_UNMOUNT_FILTER"
      ;;
    *)
      echo "❌ Invalid mount type for --force-unmount=only:<type>. Use one of: cifs, nfs, bindfs"
      exit 1
      ;;
  esac
fi

echo "=== Phase 1: Mounting network filesystems ==="
while IFS= read -r line; do
  [[ "$line" =~ ^#.*$ || -z "$line" ]] && continue
  parsed="$(parse_config_line "$line")"
  [[ $(awk -F'|' '{print NF}' <<< "$parsed") -ne 10 ]] && { echo "⚠️ Malformed line, skipping: $line"; continue; }
  IFS='|' read -r SERVER SHARE DEST TYPE MNT_UID MNT_GID MODE _ _ <<< "$parsed"
  if [[ "$TYPE" == "cifs" ]]; then
    [[ "$IN_LXC" -eq 1 ]] && { echo "Skipping CIFS mount inside LXC: $DEST"; continue; }
    CIFS_Mount "$SERVER" "$SHARE" "$DEST" "$MNT_UID" "$MNT_GID" "$MODE"
  elif [[ "$TYPE" == "nfs" ]]; then
    NFS_Mount "$SERVER" "$SHARE" "$DEST" "$MODE"
  fi
done < "$CONFIG_FILE"

echo "=== Phase 2: Mounting bindfs filesystems ==="
while IFS= read -r line; do
  [[ "$line" =~ ^#.*$ || -z "$line" ]] && continue
  parsed="$(parse_config_line "$line")"
  [[ $(awk -F'|' '{print NF}' <<< "$parsed") -ne 10 ]] && { echo "⚠️ Malformed line, skipping: $line"; continue; }
  IFS='|' read -r _ SHARE DEST TYPE MNT_UID MNT_GID _ VIEW_PERMS APPLIED_USER FILE_PERMS <<< "$parsed"
  if [[ "$TYPE" == "bindfs" ]]; then
    BINDFS_Mount "$SHARE" "$DEST" "$MNT_UID" "$MNT_GID" "$VIEW_PERMS" "$APPLIED_USER" "$FILE_PERMS"
  fi
done < "$CONFIG_FILE"

echo "=== Mount operations completed ==="
