#!/bin/bash
set -u

ROOTS=(
  "/home2/vlv/public_html"
  "/home2/vlv/www"
)

BASE_DIR="/home2/vlv/public_html/jdfs.lv"
STATE_FILE="$BASE_DIR/file-watch-state.tsv"
NEW_STATE_FILE="$BASE_DIR/file-watch-state.new.tsv"
FIND_FILE="$BASE_DIR/file-watch-find.tmp"
MAX_SECONDS=1200
START_TS=$(date +%s)

SKIP_DIRS=(
  "cache"
  "caches"
  "tmp"
  "temp"
  "logs"
  "log"
  "sessions"
  "session"
  "vendor"
  "node_modules"
  ".git"
  ".svn"
  ".idea"
  ".vscode"
  "backup"
  "backups"
  "archive"
  "archives"
  "vqcache"
)

cleanup() {
  rm -f "$NEW_STATE_FILE" "$FIND_FILE"
}
trap cleanup EXIT

is_timed_out() {
  local now
  now=$(date +%s)
  (( now - START_TS >= MAX_SECONDS ))
}

declare -A OLD_HASH
declare -A OLD_SIZE
declare -A OLD_MTIME
declare -A OLD_CTIME
declare -A SEEN
declare -A REAL_ROOTS

if [[ -f "$STATE_FILE" ]]; then
  while IFS=$'\t' read -r hash size mtime ctime path; do
    [[ -z "${path:-}" ]] && continue
    OLD_HASH["$path"]="$hash"
    OLD_SIZE["$path"]="$size"
    OLD_MTIME["$path"]="$mtime"
    OLD_CTIME["$path"]="$ctime"
  done < "$STATE_FILE"
fi

: > "$NEW_STATE_FILE"
: > "$FIND_FILE"

PRUNE_EXPR=()
first=1
for d in "${SKIP_DIRS[@]}"; do
  if (( first )); then
    first=0
  else
    PRUNE_EXPR+=("-o")
  fi
  PRUNE_EXPR+=("-name" "$d")
done

scan_root() {
  local root="$1"
  local path stat_out size rest mtime ctime hash

  [[ -d "$root" ]] || return 0

  : > "$FIND_FILE"

  find "$root" \
    \( -type d \( "${PRUNE_EXPR[@]}" \) -prune \) -o \
    -type f \
    \( -iname '*.php' \
       -o -iname '*.phtml' \
       -o -iname '*.phar' \
       -o -iname '*.sh' \
       -o -name '.htaccess' \
       -o -name '.user.ini' \
    \) \
    -print0 2>/dev/null > "$FIND_FILE"

  while IFS= read -r -d '' path; do
    if is_timed_out; then
      echo "KĻŪDA: skenēšana pārsniedza ${MAX_SECONDS} sekundes. Stāvoklis netika pārrakstīts." >&2
      exit 2
    fi

    stat_out=$(stat -c '%s|%Y|%Z' -- "$path" 2>/dev/null) || continue

    size=${stat_out%%|*}
    rest=${stat_out#*|}
    mtime=${rest%%|*}
    ctime=${rest##*|}

    if [[ -n "${OLD_HASH[$path]+x}" \
       && "${OLD_SIZE[$path]}" == "$size" \
       && "${OLD_MTIME[$path]}" == "$mtime" \
       && "${OLD_CTIME[$path]}" == "$ctime" ]]; then
      hash="${OLD_HASH[$path]}"
    else
      hash=$(sha256sum -- "$path" 2>/dev/null | awk '{print $1}') || continue
      [[ -n "$hash" ]] || continue
    fi

    SEEN["$path"]=1

    printf '%s\t%s\t%s\t%s\t%s\n' \
      "$hash" "$size" "$mtime" "$ctime" "$path" >> "$NEW_STATE_FILE"

    if [[ -z "${OLD_HASH[$path]+x}" ]]; then
      echo "JAUNS AIZDOMĪGS FAILS: $path"
    elif [[ "${OLD_HASH[$path]}" != "$hash" ]]; then
      echo "MAINĪTS AIZDOMĪGS FAILS: $path"
    fi

  done < "$FIND_FILE"
}

for root in "${ROOTS[@]}"; do
  real=$(readlink -f "$root" 2>/dev/null || true)
  [[ -n "$real" && -d "$real" ]] || continue

  if [[ -z "${REAL_ROOTS[$real]+x}" ]]; then
    REAL_ROOTS["$real"]=1
    scan_root "$real"
  fi
done

if [[ -f "$STATE_FILE" ]]; then
  for path in "${!OLD_HASH[@]}"; do
    if [[ -z "${SEEN[$path]+x}" ]]; then
      echo "IZDZĒSTS AIZDOMĪGS FAILS: $path"
    fi
  done
fi

mv -f "$NEW_STATE_FILE" "$STATE_FILE"
rm -f "$FIND_FILE"
trap - EXIT

exit 0
