#!/bin/bash
#
# Creates the cache directories the app writes to at runtime and makes them
# writable by every user that touches them (Apache/PHP-FPM for web requests,
# your login user for the CLI tools in scripts/, the chat daemon in chat/).
#
# cache/ is gitignored, so a fresh checkout has none of these. PHP does not
# create missing parent directories -- file_put_contents() to a path whose
# directory is absent just warns and writes nothing -- so without this the
# webhook logs, notification logs and phone lookups silently no-op.
#
# Safe to re-run; existing directories and their contents are left alone.
#
# Usage: scripts/setup.sh [--dry-run]

set -euo pipefail

ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"

DRY_RUN=0
if [[ "${1:-}" == "--dry-run" ]]; then
  DRY_RUN=1
elif [[ -n "${1:-}" ]]; then
  echo "usage: $(basename "$0") [--dry-run]" >&2
  exit 64
fi

# Directories written to at runtime. Each entry is a comment on what writes it.
DIRS=(
  "cache"               # php.connect.log, systems.json, topNews.json, notifs.*,
                        # 3cxEvent.*, livekit.*, gorush.*, unauth-api.*,
                        # areaCodes.sqlite, circuitStatus, vendors_analysis_*
  "cache/acms"          # backend/receiveACMStats.php -> pages/acms-dashboard.php
  "cache/appget"        # pages/account-delete.php (app store deletion records)
  "cache/mailgun"       # backend/mailgun-hook.php, backend/mailgun-message.php
  "cache/phonelookups"  # backend/ticketGetLists.php, pages/ticket/manager_calls.php
  "cache/records"       # backend/recordData.php
  "cache/user-logs"     # backend/userSaveSettings.php
  "cache/user-updates"  # code/route.inc.php session-refresh markers
  "chat/cache"          # chat/server.php packet log
)

# Log files that may already exist owned by a different user (root from a CLI
# run vs www-data from a web request); both need to keep appending.
FILES=(
  "cache/php.connect.log"
)

created=0
fixed=0
failed=0

run() {
  if [[ $DRY_RUN -eq 1 ]]; then
    return 0
  fi
  "$@"
}

# Current mode string, or a placeholder when the path is absent (dry run).
modeof() {
  local out
  out=$(ls -ld "$1" 2>/dev/null | awk '{print $1}') || true
  echo "${out:-(not created)}"
}

echo "Project root: $ROOT"
[[ $DRY_RUN -eq 1 ]] && echo "(dry run -- nothing will be changed)"
echo

# $1 = path relative to root, $2 = "dir" or "file", $3 = chmod spec
provision() {
  local rel="$1" kind="$2" mode="$3"
  local path="$ROOT/$rel" action

  if [[ -e "$path" ]]; then
    action="exists "
  else
    if [[ $kind == dir ]]; then
      run mkdir -p "$path" || { printf '  FAILED  %-22s could not create\n' "$rel"; failed=$((failed + 1)); return; }
    else
      run touch "$path" || { printf '  FAILED  %-22s could not create\n' "$rel"; failed=$((failed + 1)); return; }
    fi
    [[ $DRY_RUN -eq 1 ]] && action="missing" || action="created"
    created=$((created + 1))
  fi

  if run chmod "$mode" "$path" 2>/dev/null; then
    printf '  %s %-22s %s\n' "$action" "$rel" "$(modeof "$path")"
    fixed=$((fixed + 1))
  else
    printf '  %s %-22s chmod FAILED -- try: sudo chmod %s %s\n' "$action" "$rel" "$mode" "$path"
    failed=$((failed + 1))
  fi
}

# a+rwx on directories, not a+rw: without the execute bit nothing can traverse
# into the directory, so read/write permission on it alone is useless.
for dir in "${DIRS[@]}"; do
  provision "$dir" dir a+rwx
done

for file in "${FILES[@]}"; do
  provision "$file" file a+rw
done

echo
echo "$created created, $fixed permissions applied, $failed failed"

if [[ $failed -gt 0 ]]; then
  echo "Re-run with sudo to fix the entries above." >&2
  exit 1
fi
