#!/usr/bin/env bash
# Lawyou Firebase documents sync wrapper
# - Provides locking, pre-flight checks, retries, and logging
# - Intended to be called by cron on the VPS

set -Eeuo pipefail
IFS=$'\n\t'

# ----------------------
# Configurable settings
# ----------------------
CONTAINER_WORKDIR="${CONTAINER_WORKDIR:-/var/www/html}"
PHP_SCRIPT_PATH="${PHP_SCRIPT_PATH:-/var/www/html/documentosLawyou2FBInvoice.php}"
LOCK_FILE="${LOCK_FILE:-/tmp/lawyou_documentos_venta_fb.lock}"
LOG_FILE="${LOG_FILE:-/var/www/html/logs/sync-invoice-documents-firebase.log}"
MIN_FREE_MB="${MIN_FREE_MB:-100}"            # minimum free space required on /
PING_TARGET="${PING_TARGET:-8.8.8.8}"         # network reachability check
RETRIES="${RETRIES:-3}"
BACKOFF_SECS="${BACKOFF_SECS:-5}"
TIMEOUT_SECS="${TIMEOUT_SECS:-50}"           # timeout for php in seconds

# Safe PATH for cron environments
export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

# Ensure log directory and file exist before any logging
LOG_DIR="$(dirname "$LOG_FILE")"
mkdir -p "$LOG_DIR" || true
: >> "$LOG_FILE" || true

# ----------------------
# Helpers
# ----------------------
log() {
  local tag ts msg
  tag="$1"; shift
  ts="$(date '+%Y-%m-%dT%H:%M:%S%z')"
  msg="$*"
  echo "[$ts] [$tag] $msg" | tee -a "$LOG_FILE" >&2
}

check_command() {
  if ! command -v "$1" >/dev/null 2>&1; then
    log script "ERROR: Required command '$1' not found in PATH"
    return 1
  fi
}

check_disk_space() {
  # Check free space on root in MB
  local avail
  avail=$(df -Pm / | awk 'NR==2 {print $4}')
  if [[ -z "$avail" ]]; then
    log script "WARNING: Could not determine free disk space"
    return 0
  fi
  if (( avail < MIN_FREE_MB )); then
    log script "ERROR: Low disk space on /. Available=${avail}MB, required>=${MIN_FREE_MB}MB"
    return 1
  fi
}

check_network() {
  if command -v ping >/dev/null 2>&1; then
    if ! ping -c1 -W2 "$PING_TARGET" >/dev/null 2>&1; then
      log script "ERROR: Network check failed (ping $PING_TARGET)"
      return 1
    fi
  else
    # Fallback to curl if ping is unavailable
    if command -v curl >/dev/null 2>&1; then
      if ! curl -sSf --max-time 5 https://www.google.com >/dev/null; then
        log script "ERROR: Network check failed (curl)"
        return 1
      fi
    else
      log script "WARNING: Neither ping nor curl found; skipping network check"
    fi
  fi
}

container_running() {
  # Running inside container: no outer container state to check
  return 0
}

check_inside_container() {
  # 1) PHP binary exists and is runnable
  if ! php -v >/dev/null 2>&1; then
    log script "ERROR: 'php' not found or not runnable"
    return 1
  fi

  # 2) Script file exists and is readable
  if ! test -r "$PHP_SCRIPT_PATH"; then
    log script "ERROR: Script not found or not readable: $PHP_SCRIPT_PATH"
    ls -l "$PHP_SCRIPT_PATH" 2>&1 \
      | while IFS= read -r line; do printf "[%s] [ls] %s\n" "$(date '+%Y-%m-%dT%H:%M:%S%z')" "$line"; done \
      >> "$LOG_FILE"
    return 1
  fi

  # 3) Log directory/file permissions
  ls -ld "$LOG_DIR" >/dev/null 2>&1 && ls -l "$LOG_DIR" | head -n 20 2>/dev/null \
    | while IFS= read -r line; do printf "[%s] [logs] %s\n" "$(date '+%Y-%m-%dT%H:%M:%S%z')" "$line"; done \
    >> "$LOG_FILE" || true

  return 0
}

run_php_once() {
  # Stream PHP output and prefix each line with timestamp and tag
  log script "INFO: Exec cmd: timeout ${TIMEOUT_SECS}s php -d display_errors=1 $PHP_SCRIPT_PATH"
  timeout "$TIMEOUT_SECS" \
    php -d display_errors=1 "$PHP_SCRIPT_PATH" 2>&1 \
    | while IFS= read -r line; do printf "[%s] [php] %s\n" "$(date '+%Y-%m-%dT%H:%M:%S%z')" "$line"; done \
    >> "$LOG_FILE"
}

# ----------------------
# Main (under flock)
# ----------------------
main() {
  local start_ts end_ts attempt rc=0
  start_ts=$(date +%s)
  # Early start log to avoid silent exits
  log script "INFO: Start pid=$$ PATH=$PATH"

  # Pre-flight checks
  if ! check_command php; then
    log script "ERROR: exiting early at check_command"
    exit 1
  fi
  if ! check_disk_space; then
    log script "ERROR: exiting early at check_disk_space"
    exit 1
  fi
  if ! check_network; then
    log script "ERROR: exiting early at check_network"
    exit 1
  fi

  # No container state to verify when running inside the container

  if ! check_inside_container; then
    log script "ERROR: Preflight checks failed; exiting"
    exit 2
  fi

  # Retry loop for docker exec
  for attempt in $(seq 1 "$RETRIES"); do
    log script "INFO: Starting PHP documents (firebase) sync (attempt $attempt/$RETRIES)"
    if run_php_once; then
      log script "INFO: PHP documents (firebase) sync finished successfully"
      rc=0
      break
    else
      rc=$?
      log php "ERROR: PHP documents (firebase) sync failed with exit code $rc"
      if (( attempt < RETRIES )); then
        log script "INFO: Backing off ${BACKOFF_SECS}s before retry"
        sleep "$BACKOFF_SECS"
      fi
    fi
  done

  end_ts=$(date +%s)
  log script "INFO: Total duration: $((end_ts - start_ts))s, exit=$rc"
  return "$rc"
}

# Ensure log file exists and is writable (best-effort)
mkdir -p "$(dirname "$LOG_FILE")" 2>/dev/null || true
: >> "$LOG_FILE" 2>/dev/null || true

# Use flock to prevent overlapping runs
if command -v flock >/dev/null 2>&1; then
  # Use fd 9 for the lock file descriptor
  exec 9>"$LOCK_FILE"
  if ! flock -n 9; then
    log script "INFO: Another documents (firebase) run is in progress; exiting"
    exit 0
  fi
  # Run main with the lock held by fd 9
  if ! main; then
    exit 1
  fi
else
  # Fallback without flock using noclobber lock
  if ( set -o noclobber; echo "$$" > "$LOCK_FILE" ) 2>/dev/null; then
    trap 'rm -f "$LOCK_FILE"' EXIT INT TERM
    if ! main; then
      exit 1
    fi
  else
    log script "INFO: Another documents (firebase) run is in progress (fallback lock); exiting"
    exit 0
  fi
fi
