#!/usr/bin/env bash
#
# tools/e2e.sh — runner dos testes E2E (Playwright + axe) — ADR-025/plano 11.
#
# Resolve o runner em ordem (mesmo padrão do `tools/sniff.sh`):
#   E2E_RUNNER=host|docker  (forçado)  →  imagem Playwright já presente local  →  node no host
#   → imagem Playwright pinada (puxa na primeira vez).
# A versão do Playwright é a mesma nos dois caminhos (`src/tests-e2e/package.json`), então o
# navegador é idêntico — determinismo (ADR-001).
#
# Uso:
#   tools/e2e.sh install      # instala dependências (npm ci)
#   tools/e2e.sh typecheck    # só o type-check (tsc --noEmit)
#   tools/e2e.sh test [args]  # type-check + suíte Playwright (args repassados)
#   tools/e2e.sh report       # abre o relatório HTML
#
set -Eeuo pipefail

ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
E2E_DIR="src/tests-e2e"

# Runtime único (docker | podman): o runner em container herda o mesmo motor do stack.
# shellcheck source=tools/runtime.sh
. "$ROOT/tools/runtime.sh"

# Imagem oficial do Playwright (pinada por digest — ADR-031), casada com a versão do package.json.
E2E_IMAGE="${E2E_IMAGE:-mcr.microsoft.com/playwright:v1.64.1-noble@sha256:7852dc5a7d72f5fe458a597d690f6c42fbc8e9e26ddfa95f8e6ef552558d9bbf}"
IMAGE_REF="${E2E_IMAGE%%@*}"

# Valor de uma chave do `.env` (sem aspas) com fallback: o compose publica o app em `WEB_PORT` e a
# URL tem de acompanhar — senão o runner mede outra porta (achado F5.I2.T2-B).
env_value() {
    local key="$1" fallback="$2" value
    value="$(grep -E "^${key}=" .env 2>/dev/null | tail -1 | cut -d= -f2- | tr -d "\"' ")"
    printf '%s' "${value:-$fallback}"
}

# O app roteia por Host: `localhost` (não 127.0.0.1).
BASE_URL="${BASE_URL:-http://localhost:$(env_value WEB_PORT 50700)}"
export BASE_URL

cmd="${1:-test}"
if [ "$#" -gt 0 ]; then shift; fi

# `npm ci` exige lockfile; sem ele, `npm install` gera (primeira vez).
INSTALL_DEPS='if [ -f package-lock.json ]; then npm ci --no-audit --no-fund; else npm install --no-audit --no-fund; fi'

run_host() {
    cd "$ROOT/$E2E_DIR"
    [ -d node_modules ] || eval "$INSTALL_DEPS"

    case "$cmd" in
        install) eval "$INSTALL_DEPS" ;;
        typecheck) npm run --silent typecheck ;;
        test) npm run --silent typecheck && npx playwright test "$@" ;;
        report) npx playwright show-report "${@:-report}" ;;
        *) npx playwright "$cmd" "$@" ;;
    esac
}

# `npm ci` reescreve `node_modules` inteiro (~5-15 s): só quando o lockfile é mais novo que a
# instalação (o `npm ci` grava `node_modules/.package-lock.json`). Determinismo preservado: lockfile
# novo ⇒ reinstala.
DEPS_IF_STALE='if [ ! -d node_modules ] || [ package-lock.json -nt node_modules/.package-lock.json ]; then '"$INSTALL_DEPS"'; fi'

run_docker() {
    local script extra=''
    case "$cmd" in
        install) script="$INSTALL_DEPS" ;;
        typecheck) script="$DEPS_IF_STALE && npm run --silent typecheck" ;;
        test) script="$DEPS_IF_STALE && npm run --silent typecheck && npx playwright test" ;;
        report) script='npx playwright show-report' ;;
        *) script="npx playwright $cmd" ;;
    esac

    # Sem argumentos extras, `printf '%q '` emitiria `''` e o tsc/Playwright receberia um filtro vazio.
    if [ "$#" -gt 0 ]; then
        extra="$(printf '%q ' "$@")"
    fi

    # `--network host`: alcança o app em 127.0.0.1:$WEB_PORT do host (Linux/WHM).
    "${ENGINE[@]}" run --rm -i --init --network host "${RUN_ARGS[@]}" \
        -u "$(id -u):$(id -g)" -e HOME=/tmp \
        -e BASE_URL="$BASE_URL" -e CI="${CI:-}" \
        -v "$ROOT":/work"$MOUNT_LABEL" -w "/work/$E2E_DIR" \
        "$E2E_IMAGE" bash -lc "$script $extra"
}

if [ "${E2E_RUNNER:-auto}" = "host" ]; then
    run_host "$@"
    exit $?
fi

if [ "${E2E_RUNNER:-auto}" = "docker" ]; then
    run_docker "$@"
    exit $?
fi

if "${ENGINE[@]}" image inspect "$IMAGE_REF" >/dev/null 2>&1; then
    run_docker "$@"
elif command -v node >/dev/null 2>&1; then
    run_host "$@"
else
    run_docker "$@"
fi
