#!/bin/bash

USER="ms"
GROUP="unifi-streaming"
EXTERNAL_MINIMUM_SPACE=54683238
SRV_DIR="/srv"
SSD1_DIR="/ssd1"
JSON_DB_DIR="/etc/unifi-protect/jsonDb"

version=$(dpkg-query -W -f='${Version}' msr 2>/dev/null)
echo "#-> MSR $version pre-start"

if [ -z ${MS_TMPFS_DIR} ]; then
  echo "MS_TMPFS_DIR is not set - using default /var/opt/ms/tmp"
  MS_TMPFS_DIR="/var/opt/ms/tmp"
fi

if [ -z ${MS_INTERNAL_DIR} ]; then
  echo "MS_INTERNAL_DIR is not set - using default /data/ms"
  MS_INTERNAL_DIR="/data/ms"
fi

if [ -z ${MS_EXTERNAL_DIR} ]; then
  echo "MS_EXTERNAL_DIR is not set - using default /srv/ms"
  MS_EXTERNAL_DIR="/srv/ms"
fi


is_link() {
  [ -L "$1" ] && [ -e "$1" ] && return
  false
}

get_disk_space() {
  df "$1" -k | tail -n 1 | awk '{printf $2}'
}

isSrvReadOnly() {
  if ! command -v findmnt &> /dev/null; then
    # ignore if findmnt not found
    return 1
  fi
  # report RO state only if target mounted
  echo "Read Only file system check"
  local TMP=$(findmnt --target $SRV_DIR -o SOURCE,OPTIONS -n)
  echo $TMP
  echo $TMP | grep -E '^ro$|,ro$|,ro,|^ro,| ro'
  return $?
}

# chown only when the current owner:group differs from the desired one.
# chown() always rewrites the inode (bumping ctime), so skipping the syscall
# on already-correct entries is a real I/O saving on large trees.
chown_if_needed() {
  local spec=$1 target=$2
  [ -e "$target" ] || return 0
  local current
  current=$(stat -L -c '%U:%G' "$target" 2>/dev/null) || return 0
  [ "$current" = "$spec" ] && return 0
  chown "$spec" "$target"
}

# Same as chown_if_needed but for the symlink itself (no dereference).
chown_link_if_needed() {
  local spec=$1 target=$2
  [ -L "$target" ] || return 0
  local current
  current=$(stat -c '%U:%G' "$target" 2>/dev/null) || return 0
  [ "$current" = "$spec" ] && return 0
  chown -h "$spec" "$target"
}

# Recursive chown that touches only entries whose owner or group does not
# already match. Spec may be "user:group" or ":group".
chown_r_if_needed() {
  local spec=$1
  shift
  local u="${spec%%:*}"
  local g="${spec#*:}"
  [ "$u" = "$spec" ] && g=""
  local conds=()
  if [ -n "$u" ] && [ -n "$g" ]; then
    conds=( '(' '!' -user "$u" -o '!' -group "$g" ')' )
  elif [ -n "$u" ]; then
    conds=( '!' -user "$u" )
  elif [ -n "$g" ]; then
    conds=( '!' -group "$g" )
  else
    return 0
  fi
  local t
  for t in "$@"; do
    [ -e "$t" ] || continue
    find "$t" "${conds[@]}" -exec chown -h "$spec" {} + 2>/dev/null
  done
}

usermod -g ${GROUP} ${USER}

if [ -d "/etc" ]; then
  mkdir -p /etc/msr || true
  chown_r_if_needed "${USER}:${GROUP}" /etc/msr || true
  chmod -R ug+rw /etc/msr || true
fi

if [ -d $JSON_DB_DIR ]; then
  echo "Make sure JSON DB directory $JSON_DB_DIR is readable"
  chown_r_if_needed ":${GROUP}" "$JSON_DB_DIR" || true
  chmod -R ug+r "$JSON_DB_DIR" || true
fi

# External storage available
if (mountpoint -q $SRV_DIR || is_link $SRV_DIR) && [ $(get_disk_space $SRV_DIR) -ge $EXTERNAL_MINIMUM_SPACE ] && (! isSrvReadOnly); then
  echo "External storage available"

  if [ ! -d $MS_EXTERNAL_DIR ]; then
    echo "Creating external directory $MS_EXTERNAL_DIR"
    mkdir -p "${MS_EXTERNAL_DIR}/logs"
    echo "Changing owner for $MS_EXTERNAL_DIR to $USER:$GROUP (if needed)"
    chown_if_needed "${USER}:${GROUP}" "${MS_EXTERNAL_DIR}" || true
    echo "Setting group permissions for $MS_EXTERNAL_DIR"
    chmod -R g+rw "${MS_EXTERNAL_DIR}"
    echo "Changing owner for $MS_EXTERNAL_DIR/logs to $USER:$GROUP (if needed)"
    chown_if_needed "${USER}:${GROUP}" "${MS_EXTERNAL_DIR}/logs" || true
    chmod -R g+rw "${MS_EXTERNAL_DIR}/logs"
  fi

  # Ensure logs/ exists even when the root dir was created by a previous run.
  # Non-recursive on purpose: this is the cheap per-boot guarantee, distinct
  # from the one-time recursive chmod inside the directory-creation block above.
  # Reject a service-user-planted symlink so the root chown/chmod below can't follow it to e.g. /etc.
  if [ -L "${MS_EXTERNAL_DIR}/logs" ]; then
    rm -f -- "${MS_EXTERNAL_DIR}/logs"
  fi
  mkdir -p "${MS_EXTERNAL_DIR}/logs"
  chown -h "${USER}:${GROUP}" "${MS_EXTERNAL_DIR}/logs" || true
  if [ ! -L "${MS_EXTERNAL_DIR}/logs" ]; then
    chmod g+rw "${MS_EXTERNAL_DIR}/logs" || true
  fi

  if [ -d $MS_INTERNAL_DIR ]; then
    echo "Checking if internal directory $MS_INTERNAL_DIR is empty"
    if [ "$(find ${MS_INTERNAL_DIR}/ -maxdepth 1 -mindepth 1 -type d | wc -l)" -gt 0 ]; then
      TIMESTAMP=$(date +"%Y-%m-%d_%H%M%S")
      DEST_DIR="$MS_EXTERNAL_DIR/$TIMESTAMP"
      echo "Creating directory $DEST_DIR"
      mkdir -p "$DEST_DIR"
      echo "Moving internal directory $MS_INTERNAL_DIR to external directory $DEST_DIR"
      if rsync -av -- "$MS_INTERNAL_DIR/" "$DEST_DIR/"; then
        echo "Removing internal directory $MS_INTERNAL_DIR"
        rm -rf -- "${MS_INTERNAL_DIR:?}"/*
        echo "Internal directory $MS_INTERNAL_DIR cleaned"
      else
        echo "Migration copy to $DEST_DIR failed, keeping internal directory $MS_INTERNAL_DIR" >&2
      fi
    fi
  fi
else
  echo "Using internal storage"

  if [ ! -d $MS_INTERNAL_DIR ]; then
    echo "Creating internal directory $MS_INTERNAL_DIR"
    mkdir -p "${MS_INTERNAL_DIR}/logs"
    echo "Changing owner for $MS_INTERNAL_DIR to $USER:$GROUP (if needed)"
    chown_if_needed "${USER}:${GROUP}" "${MS_INTERNAL_DIR}" || true
    echo "Setting group permissions for $MS_INTERNAL_DIR"
    chmod -R g+rw "${MS_INTERNAL_DIR}"
    echo "Setting group permissions for $MS_INTERNAL_DIR/logs"
    chown_if_needed "${USER}:${GROUP}" "$MS_INTERNAL_DIR/logs" || true
    echo "Setting group permissions for $MS_INTERNAL_DIR/logs"
    chmod -R g+rw "${MS_INTERNAL_DIR}/logs"
  fi

  # Ensure logs/ exists even when the root dir was created by a previous run.
  # Non-recursive on purpose: this is the cheap per-boot guarantee, distinct
  # from the one-time recursive chmod inside the directory-creation block above.
  # Reject a service-user-planted symlink so the root chown/chmod below can't follow it to e.g. /etc.
  if [ -L "${MS_INTERNAL_DIR}/logs" ]; then
    rm -f -- "${MS_INTERNAL_DIR}/logs"
  fi
  mkdir -p "${MS_INTERNAL_DIR}/logs"
  chown -h "${USER}:${GROUP}" "${MS_INTERNAL_DIR}/logs" || true
  if [ ! -L "${MS_INTERNAL_DIR}/logs" ]; then
    chmod g+rw "${MS_INTERNAL_DIR}/logs" || true
  fi
fi

if [ -d ${MS_INTERNAL_DIR} ]; then
  if [ -L $MS_INTERNAL_DIR ]; then
    echo "Changing owner for $MS_INTERNAL_DIR to $USER:$GROUP (if needed)"
    chown_link_if_needed "$USER:$GROUP" "$MS_INTERNAL_DIR" || true
    chown_r_if_needed "$USER:$GROUP" "$MS_INTERNAL_DIR/" || true
  else
    echo "Changing owner for $MS_INTERNAL_DIR to $USER:$GROUP (if needed)"
    chown_r_if_needed "$USER:$GROUP" "$MS_INTERNAL_DIR" || true
  fi
fi

if [ -d $MS_EXTERNAL_DIR ]; then
  echo "Changing owner for $MS_EXTERNAL_DIR to $USER:$GROUP (if needed)"
  chown_if_needed "$USER:$GROUP" "$MS_EXTERNAL_DIR" || true
  mapfile -d '' EXTERNAL_SUBDIRS < <(find "$MS_EXTERNAL_DIR" -mindepth 1 -maxdepth 1 -type d -print0)
  if [ ${#EXTERNAL_SUBDIRS[@]} -gt 0 ]; then
    chown_r_if_needed "$USER:$GROUP" "${EXTERNAL_SUBDIRS[@]}" || true
  fi
  echo "Directory $MS_EXTERNAL_DIR ready"
fi

if [ -e $SSD1_DIR ]; then
  echo "SSD1 storage available"
  if [ ! -d $SSD1_DIR/unifi-protect/video ]; then
    echo "Creating SSD1 directory $SSD1_DIR/unifi-protect/video"
    mkdir -p "$SSD1_DIR/unifi-protect/video" || true
    echo "Changing owner for $SSD1_DIR/unifi-protect to $USER:$GROUP (if needed)"
    chown_r_if_needed "${USER}:${GROUP}" "$SSD1_DIR/unifi-protect" || true
    echo "Setting group permissions for $SSD1_DIR/unifi-protect"
    chmod -R ug+rw "$SSD1_DIR/unifi-protect" || true
  fi
fi

echo "<-# MSR $version pre-start"
