#!/bin/bash

PKG="unifi-protect"
USER="unifi-protect"
GROUP="unifi-streaming"

DB_USER="unifi-protect"
DB_PORT=5433
LOGS_DIR="/var/log/$PKG"
EXTERNAL_MINIMUM_SPACE=54683238 # kibibyte = 52.15 GiB = 56 GB
COUNTER="/tmp/.protect.cnt"
RUN_DIR="/var/run/unifi-protect"

if [ -z $UFP_INTERNAL_DIR ] && [ -z $UFP_EXTERNAL_DIR ]; then
  echo "############## FAILED! neither UFP_INTERNAL_DIR or UFP_EXTERNAL_DIR is set, exiting #########" 1>&2
  exit 1
fi

# Create DB user
su postgres -c "createuser $DB_USER -p $DB_PORT -d" || true

usermod -g $GROUP $USER

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

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

# clean up ems log if too big
clean_up_oversized_log() {
  local dir=$1
  local log_path="$dir/logs"

  [ -d $log_path ] && find "$log_path" -name "*.log" -type f -size +20M -exec rm -f '{}' \;
}

saveJournals() {
  # Check if journalctl is available
  if ! command -v journalctl &> /dev/null; then
    echo "journalctl command not found. Make sure you have systemd installed."
    return 1
  fi

  unit_name="$PKG.service"
  log_file="/tmp/.lastProtectJournal"
  alljournal_file="/tmp/journal-all"
  journalctl -u "$unit_name" --since "1 minute ago" > "$log_file"
  journalctl --all --since '1 hours ago' > $alljournal_file
  chown $USER:$GROUP $log_file $alljournal_file

  echo "Journal log saved to $log_file and $alljournal_file"
}

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 -o SOURCE,OPTIONS -n)
  echo $TMP
  echo $TMP | grep -E '^ro$|,ro$|,ro,|^ro,| ro'
  return $?
}

run_rescue() {
  rescueDir="/usr/share/unifi-protect/app/hooks/rescue/"

  # Find all scripts in the rescue directory, sorted by date in their filename
  for script in $(ls "$rescueDir" | grep -E '^[0-9]{8}-.+\.sh$' | sort); do
    full_script_path="$rescueDir/$script"

    if [ -x "$full_script_path" ]; then
      $full_script_path
    fi
  done
}

# Adding this run's timestamp to the counter file
# Truncating the counter file to the last 8 timestamps max
update_restart_counter() {
  date +%s >> $COUNTER
  echo "$(tail -n8 $COUNTER)" > $COUNTER
  chown $USER:$GROUP $COUNTER 2>&1 >/dev/null
}

saveJournals

# Internal directory most exist! Fallback path requires it to create logger
if [ ! -d $UFP_INTERNAL_DIR ]; then
  # Create internal directory
  mkdir $UFP_INTERNAL_DIR
  chown $USER:$GROUP $UFP_INTERNAL_DIR
fi

if [ -d $UFP_INTERNAL_DIR ]; then
  UFP_VIDEO_DIR="${UFP_INTERNAL_DIR}/video"
  UFP_EXPORTS_DIR="${UFP_INTERNAL_DIR}/exports"
fi

# External storage available
if (mountpoint -q /srv || is_link /srv) && [ $(get_disk_space /srv) -ge $EXTERNAL_MINIMUM_SPACE ] && (! isSrvReadOnly); then
  if [ ! -d $UFP_EXTERNAL_DIR ]; then
    # Create external directory
    mkdir $UFP_EXTERNAL_DIR
    chown $USER:$GROUP $UFP_EXTERNAL_DIR
  fi

  UFP_VIDEO_DIR="${UFP_EXTERNAL_DIR}/video"
  UFP_EXPORTS_DIR="${UFP_EXTERNAL_DIR}/exports"

  if [ "$(find ${UFP_INTERNAL_DIR}/ -maxdepth 1 -mindepth 1 -type d -not -name 'logs' -not -name 'video' | wc -l)" -gt 0 ] \
    || [ "$(find ${UFP_INTERNAL_DIR}/video -type f -not -name '*_thumbnails_*.ubv' -print -quit 2>/dev/null)" ]; then
    # Extend systemd start timeout for internal→external data migration.
    # Default TimeoutStartSec (300s) is insufficient when stopping media services (~90s)
    # plus rsync on large datasets or degraded RAID can exceed the remaining budget.
    # 900s (15 min) covers worst-case: service stops + rsync + DB path updates.
    systemd-notify "EXTEND_TIMEOUT_USEC=900000000" 2>/dev/null || true

    systemctl stop ms 2>/dev/null || true
    systemctl stop msr 2>/dev/null || true
    systemctl stop msp 2>/dev/null || true
    systemctl stop mst 2>/dev/null || true
    systemctl stop ds 2>/dev/null || true

    # Unmount temp filesystem from internal directory, ignore if not exists
    umount -l $UFP_INTERNAL_DIR/temp 2>/dev/null || true

    # Move everything to external directory except logs and thumbnail UBV files.
    # Thumbnail recordings should remain on internal storage (SSD) for fast access.
    rsync --exclude 'logs' --exclude '*_thumbnails_*.ubv' -a $UFP_INTERNAL_DIR/ $UFP_EXTERNAL_DIR/

    # Update DB records, due to we support motion only recording if NVR has buildIn SSD.
    # Skip thumbnail recordings - they remain on internal storage.
    psql -U $DB_USER -p $DB_PORT -c "UPDATE \"recordingFiles\" SET folder = REPLACE(folder, '/data/unifi-protect', '/srv/unifi-protect') WHERE type IS DISTINCT FROM 'thumbnails'"
    psql -U $DB_USER -p $DB_PORT -c "UPDATE \"backupFiles\" SET path = REPLACE(path, '/data/unifi-protect', '/srv/unifi-protect')"
    psql -U $DB_USER -p $DB_PORT -c "UPDATE \"updates\" SET path = REPLACE(path, '/data/unifi-protect', '/srv/unifi-protect')"

    # Delete data on internal directory except logs and thumbnail UBV files.
    # First remove all non-video, non-logs top-level directories
    find "${UFP_INTERNAL_DIR}" -mindepth 1 -maxdepth 1 -not -name 'logs' -not -name 'video' -exec rm -rf {} +
    # Then remove non-thumbnail files from video directory
    find "${UFP_INTERNAL_DIR}/video" -type f -not -name '*_thumbnails_*.ubv' -delete 2>/dev/null || true
    # Clean up empty directories in video, preserving directory structure for remaining thumbnails
    find "${UFP_INTERNAL_DIR}/video" -mindepth 1 -type d -empty -delete 2>/dev/null || true
    # After moving data to external, restart MS
    systemctl start ms 2>/dev/null || true
    systemctl start msr 2>/dev/null || true
    systemctl start msp 2>/dev/null || true
    systemctl start mst 2>/dev/null || true
    systemctl start ds 2>/dev/null || true
  fi

  # Check disk has enough free spaces to start Protect
  free_spaces=$(df -k /srv | tail -n 1 | awk '{printf $4}')
  # disk quota hard limit is 16G, set the MIN_SPACES to 20 GB
  MIN_SPACES=20971520
  GB=1048576
  if [ "${free_spaces}" -lt "${MIN_SPACES}" ]; then
    echo "Not enough free spaces to start Protect, free spaces: ${free_spaces} KB, required: ${MIN_SPACES} KB"
    du -h -d 1 /srv/

    num=$(((MIN_SPACES - free_spaces) / GB + 1))

    [ -d $UFP_VIDEO_DIR ] && find $UFP_VIDEO_DIR -type f -printf '%T+ %p\n' | grep '0_rotating' | sort | head -n ${num} | awk '{print $2}' | xargs rm -vf

    echo "Free up ${num} GB spaces, now free spaces: $(df -k /srv | tail -n 1 | awk '{printf $4}') KB"
  fi
fi

# Support directories
mkdir -p $UFP_BACKUPS_DIR $UFP_JSONDB_DIR $LOGS_DIR $RUN_DIR
chown -R $USER:$GROUP $UFP_BACKUPS_DIR $UFP_JSONDB_DIR $LOGS_DIR $RUN_DIR

if [ -d $UFP_INTERNAL_DIR ]; then
  echo "############################ Setting [$USER:$GROUP] ownership on UFP_INTERNAL_DIR=[${UFP_INTERNAL_DIR}] ###########################" 1>&2
  clean_up_oversized_log $UFP_INTERNAL_DIR

  if [ -L $UFP_INTERNAL_DIR ]; then
    chown -c -h $USER:$GROUP $UFP_INTERNAL_DIR
    chown -c -R $USER:$GROUP $UFP_INTERNAL_DIR/ | tail -n 10
  else
    chown -c -R $USER:$GROUP $UFP_INTERNAL_DIR | tail -n 10
  fi
fi

if [ -d $UFP_EXTERNAL_DIR ]; then
  echo "############################# Setting [$USER:$GROUP] ownership on UFP_EXTERNAL_DIR=[${UFP_EXTERNAL_DIR}] #######################" 1>&2
  clean_up_oversized_log $UFP_EXTERNAL_DIR
  chown -c $USER:$GROUP $UFP_EXTERNAL_DIR
  cv_path="$UFP_EXTERNAL_DIR/cv"
  find $UFP_EXTERNAL_DIR -mindepth 1 -maxdepth 1 -type d -not -path "$cv_path" -not -path "$UFP_VIDEO_DIR" -prune -exec chown -c -R $USER:$GROUP {} + | tail -n 10
  [ -d "$cv_path" ] && find $cv_path -maxdepth 1 -type d -exec chown -c $USER:$GROUP {} +
fi

mkdir -p $UFP_VIDEO_DIR || true

if [ -d $UFP_VIDEO_DIR ]; then
  chmod g+rw $UFP_VIDEO_DIR || true
  chown :$GROUP $UFP_VIDEO_DIR || true
  echo "############################# Setting group ${GROUP} ownership and permissions on ${UFP_VIDEO_DIR} ##############################" 1>&2
  # This is faster than changing permissions for all files
  find $UFP_VIDEO_DIR ! -perm -g=w -exec chmod g+rw {} + || true
  find $UFP_VIDEO_DIR ! -group "$GROUP" -exec chown :$GROUP {} + || true
  echo "############################# Setting group ${GROUP} ownership and permissions on ${UFP_VIDEO_DIR} OK ##########################" 1>&2
else
  echo "############################ FAILED! Could not set-up UFP_VIDEO_DIR=${UFP_VIDEO_DIR} exiting ##########################" 1>&2
  exit 1
fi

mkdir -p $UFP_EXPORTS_DIR || true

if [ -d $UFP_EXPORTS_DIR ]; then
  chmod g+rw $UFP_EXPORTS_DIR || true
  chown :$GROUP $UFP_EXPORTS_DIR || true
  echo "############################# Setting group ${GROUP} ownership and permissions on ${UFP_EXPORTS_DIR} ##############################" 1>&2
  # This is faster than changing permissions for all files
  find $UFP_EXPORTS_DIR ! -perm -g=w -exec chmod g+rw {} + || true
  find $UFP_EXPORTS_DIR ! -group "$GROUP" -exec chown :$GROUP {} + || true
  echo "############################# Setting group ${GROUP} ownership and permissions on ${UFP_EXPORTS_DIR} OK ##########################" 1>&2
else
  echo "############################ FAILED! Could not set-up UFP_EXPORTS_DIR=${UFP_EXPORTS_DIR} exiting ##########################" 1>&2
  exit 1
fi

echo "########## Video path UFP_VIDEO_DIR=[${UFP_VIDEO_DIR}] #########" 1>&2

# protect won't start on $UFP_EXTERNAL_DIR
if isSrvReadOnly; then
  touch /etc/$PKG/jsonDb/.hdd_corrupted
fi

update_certificates_access() {
  chmod a+r /data/unifi-core/config/unifi-core.crt || true
  chmod a+r /data/unifi-core/config/unifi-core.key || true
}

run_rescue
update_restart_counter
update_certificates_access
