#!/usr/bin/env bash
# nplus1-scan.sh
# Run a targeted artisan command to surface potential N+1 queries (no unit tests involved).

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

PROJECT_ROOT="$(cd "$(dirname "$0")" && pwd)"
LOG_DIR="$PROJECT_ROOT/.quality-check-logs"
mkdir -p "$LOG_DIR"
LOG_FILE="$LOG_DIR/nplus1.log"

TRIGGER_CMD=${1:-"nplus1:trigger"}
THRESHOLD=${NPLUS1_THRESHOLD:-2}
FRESH=${FRESH_LOG:-1}
[ "$FRESH" = "1" ] && : > "$LOG_FILE"

is_tty() { [ -t 1 ]; }
blue() { is_tty && printf '\e[34m%s\e[0m' "$1" || printf '%s' "$1"; }
yellow() { is_tty && printf '\e[33m%s\e[0m' "$1" || printf '%s' "$1"; }
red() { is_tty && printf '\e[31m%s\e[0m' "$1" || printf '%s' "$1"; }
info() { printf "%s %s\n" "$(blue [INFO])" "$*"; }
warn() { printf "%s %s\n" "$(yellow [WARN])" "$*"; }
err()  { printf "%s %s\n" "$(red [ERROR])" "$*"; }
timestamp() { date '+%Y-%m-%d %H:%M:%S'; }
log_line() { printf '[%s] %s\n' "$(timestamp)" "$*" >> "$LOG_FILE"; }

info "Starting N+1 scan (trigger: $TRIGGER_CMD; threshold: $THRESHOLD)"

if ! command -v php >/dev/null 2>&1 || [ ! -f "$PROJECT_ROOT/artisan" ]; then
  err "artisan not found"; exit 2
fi
if ! composer show beyondcode/laravel-query-detector > /dev/null 2>&1; then
  warn "beyondcode/laravel-query-detector not installed"; exit 2
fi
if ! php artisan list --raw | grep -q "^$TRIGGER_CMD\\b"; then
  err "Artisan command '$TRIGGER_CMD' not found"; exit 2
fi

export QUERY_DETECTOR_ENABLED=1 APP_ENV=local APP_DEBUG=1

set +e
php artisan "$TRIGGER_CMD" >> "$LOG_FILE" 2>&1
TRIGGER_EXIT=$?
set -e
[ $TRIGGER_EXIT -ne 0 ] && warn "Trigger exit code: $TRIGGER_EXIT (continuing)" && log_line "TRIGGER_EXIT=$TRIGGER_EXIT"

# Build a simplified multiline-aware SELECT capture
SANITIZED=$(awk 'BEGIN{ORS="\n"} {line=$0; gsub(/`/,"",line); if(tolower(line) ~ /^select /){printf "%s", line; pending=1} else if(pending && /from /){printf " %s\n", line; pending=0} else if(pending){printf " %s", line}}' "$LOG_FILE")

mapfile -t SELECTS < <(printf '%s' "$SANITIZED" | grep -Eoi '^select .* from .*' | sed -E 's/ +/ /g' | sed -E 's/=[0-9]+/=N/g' | tr 'A-Z' 'a-z' | head -n 8000)

if [ ${#SELECTS[@]} -eq 0 ]; then
  info "No SQL SELECT statements found"; log_line "N+1:SUCCESS:NO_SQL"; exit 0
fi

declare -A COUNT
for s in "${SELECTS[@]}"; do
  [[ -n "$s" ]] && COUNT["$s"]=$(( ${COUNT["$s"]:-0} + 1 ))
done

FOUND=0
for sql in "${!COUNT[@]}"; do
  if [ ${COUNT[$sql]} -ge $THRESHOLD ]; then
    (( FOUND==0 )) && warn "Candidates (>= $THRESHOLD repeats):" && log_line "NPLUS1:BEGIN"
    FOUND=1
    warn "(${COUNT[$sql]}) $sql"; log_line "NPLUS1:CANDIDATE:count=${COUNT[$sql]} sql=$sql"
  fi
done

if [ $FOUND -eq 0 ]; then
  info "N+1: SUCCESS (no repeated queries meeting threshold $THRESHOLD)"; log_line "N+1:SUCCESS"; exit 0
else
  info "N+1: DETECTED"; log_line "N+1:DETECTED"; exit 1
fi
