#!/usr/bin/env bash
# ============================================================
# storage_engine Benchmark — Parallel (real-world simulation)
#
# Queries run with JIT=on and up to 16 parallel workers to
# simulate production workloads where the query executor
# exploits multi-core CPUs. This scenario shows the benefit
# of columnar vectorized execution in parallel contexts.
#
# Usage:
#   bash run_parallel.sh [N_RUNS]   (default 3)
#
# Outputs:
#   results_parallel.csv            — raw median timings
#   benchmark_parallel.png / .svg   — chart (requires chart_parallel.py)
# ============================================================
set -euo pipefail
export LC_ALL=C

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
RESULTS="${RESULTS:-$SCRIPT_DIR/results_parallel_nocitus.csv}"
RUNS=${1:-3}
AM_DB="${AM_DB:-bench_am}"
PG_USER="$(whoami)"
PGPORT="${PGPORT:-5432}"
PG_VERSION_LABEL="${PG_VERSION_LABEL:-18}"
MAX_PARALLEL_WORKERS_PER_GATHER="${MAX_PARALLEL_WORKERS_PER_GATHER:-4}"
ENABLE_COLUMN_CACHE="${ENABLE_COLUMN_CACHE:-off}"
COLUMN_CACHE_SIZE="${COLUMN_CACHE_SIZE:-200}"

declare -a Q_LABELS=(
  "Q1 count(*)"
  "Q2 SUM/AVG numeric+double"
  "Q3 GROUP BY country (10)"
  "Q4 GROUP BY event_type+p95"
  "Q5 date range 1 month"
  "Q6 JSONB @> GIN"
  "Q7 JSONB key + GROUP BY"
  "Q8 array @> GIN"
  "Q9 LIKE text scan"
  "Q10 heavy multi-agg"
)

declare -a QUERIES=(
  "SELECT COUNT(*) FROM __TBL__"
  "SELECT SUM(amount),AVG(amount),SUM(price),AVG(price) FROM __TBL__"
  "SELECT country_code,COUNT(*) AS n,AVG(score) FROM __TBL__ GROUP BY country_code ORDER BY n DESC"
  "SELECT event_type,COUNT(*),SUM(amount),AVG(duration_ms),percentile_disc(0.95) WITHIN GROUP (ORDER BY duration_ms) FROM __TBL__ GROUP BY event_type ORDER BY SUM(amount) DESC NULLS LAST"
  "SELECT event_date,COUNT(*),SUM(amount),AVG(price) FROM __TBL__ WHERE event_date BETWEEN '2024-01-01' AND '2024-01-31' GROUP BY event_date ORDER BY event_date"
  "SELECT COUNT(*),AVG(amount) FROM __TBL__ WHERE metadata @> '{\"os\":\"android\"}'"
  "SELECT metadata->>'campaign',COUNT(*),SUM(amount) FROM __TBL__ WHERE metadata ? 'campaign' GROUP BY 1 ORDER BY 3 DESC NULLS LAST"
  "SELECT COUNT(*),AVG(price) FROM __TBL__ WHERE tags @> ARRAY['tag_5']"
  "SELECT COUNT(*),SUM(amount) FROM __TBL__ WHERE url LIKE '/page/1%'"
  "SELECT browser,is_mobile,COUNT(*),SUM(amount),AVG(amount),MIN(amount),MAX(amount),SUM(price*quantity),AVG(duration_ms),COUNT(DISTINCT country_code),SUM(CASE WHEN event_type='purchase' THEN amount END) FROM __TBL__ GROUP BY browser,is_mobile ORDER BY COUNT(*) DESC"
)

declare -A AM_TARGETS=(
  ["heap"]="$AM_DB:events_heap"
  ["colcompress"]="$AM_DB:events_col"
  ["rowcompress"]="$AM_DB:events_row"
)
declare -a AM_ORDER=("heap" "colcompress" "rowcompress")

psql_ms() {
    local db="$1" tbl="$2" q_tmpl="$3"
    local q="${q_tmpl//__TBL__/$tbl}"
    local tmpf
    tmpf=$(mktemp /tmp/bench_XXXXXX.sql)
    if [[ "$ENABLE_COLUMN_CACHE" == "on" ]]; then
        printf '\\timing on\nSET jit=off;\nSET max_parallel_workers_per_gather=%s;\nSET storage_engine.enable_column_cache=on;\nSET storage_engine.column_cache_size=%s;\n%s;\n' "$MAX_PARALLEL_WORKERS_PER_GATHER" "$COLUMN_CACHE_SIZE" "$q" > "$tmpf"
    else
        printf '\\timing on\nSET jit=off;\nSET max_parallel_workers_per_gather=%s;\n%s;\n' "$MAX_PARALLEL_WORKERS_PER_GATHER" "$q" > "$tmpf"
    fi

    local -a times=()
    for ((i=0; i<RUNS; i++)); do
    local output
    local t
    if ! output=$(psql -U "$PG_USER" -p "$PGPORT" -d "$db" --no-psqlrc -P pager=off -f "$tmpf" 2>&1); then
      rm -f "$tmpf"
      printf 'benchmark query failed for %s.%s\n%s\n' "$db" "$tbl" "$output" >&2
      return 1
    fi
    t=$(printf '%s\n' "$output" | grep -oP '(?:Time|Tempo):\s*\K[0-9]+[.,][0-9]+' | tail -1 | tr ',' '.' || true)
    if [[ -z "$t" ]]; then
      rm -f "$tmpf"
      printf 'benchmark timing parse failed for %s.%s\n%s\n' "$db" "$tbl" "$output" >&2
      return 1
    fi
    times+=("$t")
    done
    rm -f "$tmpf"
    printf '%s\n' "${times[@]}" | LC_ALL=C sort -n | LC_NUMERIC=C awk "NR==$(( (RUNS+1)/2 )) {printf \"%.3f\", \$1}"
}

echo "AM,query,median_ms" > "$RESULTS"

echo "============================================================"
echo " Benchmark — PostgreSQL $PG_VERSION_LABEL  •  1 000 000 rows"
echo " Runs per query: $RUNS   JIT: on   Parallelism: $MAX_PARALLEL_WORKERS_PER_GATHER workers"
echo " Column cache: $ENABLE_COLUMN_CACHE  (size: ${COLUMN_CACHE_SIZE} MB)"
echo "============================================================"

for am in "${AM_ORDER[@]}"; do
    target="${AM_TARGETS[$am]}"
    db="${target%%:*}"
    tbl="${target##*:}"
    echo ""
    echo "── $am  (db: $db  table: $tbl) ─────────────────────────"
    for i in "${!Q_LABELS[@]}"; do
        ms=$(psql_ms "$db" "$tbl" "${QUERIES[$i]}")
        label="${Q_LABELS[$i]}"
        printf "  %-35s  %s ms\n" "$label" "$ms"
        echo "$am,\"$label\",$ms" >> "$RESULTS"
    done
done

echo ""
echo "Results saved → $RESULTS"
echo "Generate chart: python3 $SCRIPT_DIR/chart_parallel.py $RESULTS"
