#!/usr/bin/env bash
#
# tools/coverage-parallel.sh — PHPUnit paralelo com cobertura mesclada (ADR-038).
#
# O PHPUnit roda a suíte inteira num único processo (~37 s). O ParaTest divide os arquivos de
# teste entre workers, mantendo a cobertura: cada worker grava um arquivo de cobertura e o
# ParaTest mescla no clover/cobertura final. Todos os testes usam banco isolado por worker
# (`concordia_test_<token>`, ver Tests\TestCase).
#
# Determinismo: os bancos dos workers são recriados a cada execução e migrados pelo próprio
# RefreshDatabase do primeiro teste do worker. Nada de estado herdado de uma rodada anterior.
#
# Env:
#   COVERAGE_WORKERS=4      número de processos (1..16)
#   COVERAGE_KEEP_DB=1      mantém os bancos dos workers para depuração
set -Eeuo pipefail

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

BASE_DB="${TEST_DB:-concordia_test}"
WORKERS="${COVERAGE_WORKERS:-4}"
DB_USER="${DB_USERNAME:-concordia}"
PROJECT="$(bash "$ROOT/tools/project-name.sh" 2>/dev/null)"
# shellcheck source=tools/runtime.sh
. "$ROOT/tools/runtime.sh"
COMPOSE=("${ENGINE[@]}" compose -p "$PROJECT" --env-file .env "${COMPOSE_FILES[@]}")

if ! [[ "$WORKERS" =~ ^([1-9]|1[0-6])$ ]]; then
    echo "coverage-parallel: COVERAGE_WORKERS inválido: $WORKERS (use 1..16)." >&2
    exit 2
fi

psql() {
    local database="$1" sql="$2"
    "${COMPOSE[@]}" exec -T postgres psql -U "$DB_USER" -d "$database" -v ON_ERROR_STOP=1 -c "$sql"
}

drop_worker() {
    psql postgres "DROP DATABASE IF EXISTS ${BASE_DB}_$1 WITH (FORCE);" >/dev/null
}

create_worker() {
    psql postgres "CREATE DATABASE ${BASE_DB}_$1;" >/dev/null
}

cleanup() {
    if [ "${COVERAGE_KEEP_DB:-0}" = "1" ]; then
        return
    fi

    local i
    for i in $(seq 1 "$WORKERS"); do
        drop_worker "$i" 2>/dev/null || true
    done
}
trap cleanup EXIT

# O banco base existe por compatibilidade (PHPUnit serial/Infection); o paralelo não o usa.
bash "$ROOT/tools/test-db.sh" "$BASE_DB" >/dev/null

for i in $(seq 1 "$WORKERS"); do
    drop_worker "$i"
    create_worker "$i"
done

mkdir -p build/coverage

# O worker do ParaTest define `TEST_TOKEN`; o TestCase troca `DB_DATABASE` para
# `concordia_test_<token>` antes do boot da aplicação.
#
# `memory_limit` do **processo de mesclagem** (o runner do ParaTest, que junta os clovers depois
# dos workers): medido em 2026-10-26 com o probe `memory_get_peak_usage(true)` — **286 412 800 B
# (273 MiB)** no pico da mesclagem de 1 602 testes. O teto de 256 MiB do `php.ini` (CLI) ficava
# 17 MiB abaixo e o merge abortava em `HitMap.php` **depois** de todos os testes passarem. 512 MiB
# dá ~1,9x de folga para o crescimento da suíte. O limite do **pool FPM** (256 MiB,
# `php_admin_value`) não muda: é request servido, não ferramenta de build (ADR-020).
"${COMPOSE[@]}" exec -T php-fpm php -d memory_limit=512M -d pcov.enabled=1 -d pcov.directory=src \
    ./vendor/bin/paratest \
    --processes="$WORKERS" \
    --coverage-clover build/coverage/clover.xml \
    --coverage-cobertura build/coverage/cobertura.xml \
    --coverage-text \
    --passthru-php="'-d' 'pcov.enabled=1' '-d' 'pcov.directory=src'"
