#!/bin/sh
#
# Os blocos do laboratorio de migracao param quando nao estao no clone dele?
#
#     sh scripts/ensaiar-blocos-do-laboratorio.sh
#     sh scripts/ensaiar-blocos-do-laboratorio.sh <copia da docs/ambiente-homologacao.md>
#
# Sai com 0 quando todo bloco faz o que deve nos tres casos abaixo; 1 quando
# algum nao faz, e diz qual; 2 quando nao consegue medir (a secao nao esta onde
# devia, um bloco que ele esperava sumiu, ou falta `mktemp`). O argumento aponta
# o ensaio para uma COPIA do documento -- e como se falsifica sem tocar no
# arquivo de verdade.
#
# ---------------------------------------------------------------------------
# POR QUE ISTO EXISTE (08/10/2026, D431)
#
# O dono decidiu (pergunta 37 da pagina do lote, a opcao (a)) que o laboratorio
# de migracao sobe de um clone proprio, `~/franquiabv-lab`, ao lado do da
# homologacao no BVIP. O MESMO texto, rodado do clone da homologacao, vai a
# homologacao: o `docker compose` le o `.env` do diretorio em que se esta, e o
# `cp` do `local.postgres.php.dist` aponta o `local.php` dali para o
# PostgreSQL -- que e o defeito do D431. A primeira versao da secao abria cada
# bloco por
#
#     cd ~/franquiabv-lab && grep -qx 'COMPOSE_PROJECT_NAME=franquiabv-lab' .env || echo "PARE"
#
# e a revisao mostrou que a conferencia so AVISAVA: o `echo` sai com 0, e as
# linhas de baixo rodavam assim mesmo, no diretorio em que se estava. O
# portao `conferir-provedores-no-loopback.php` lia que o `cd` estava no texto,
# e nao que ele segurava. Este ensaio pergunta o que importa: fora do clone,
# alguma coisa rodou?
#
# ---------------------------------------------------------------------------
# COMO
#
# Tira da secao "Laboratorio de migracao (Fase 1)" cada bloco `bash` que age --
# um `docker compose`, um `cp`, um `git clone`, um `gunzip` ou um roteiro de
# `scripts/` fora de comentario -- e roda o MESMO texto num diretorio
# temporario: o `$HOME` e outro, e o diretorio de onde se cola e um clone de
# mentira da homologacao, com um `.env` e um `local.php` que dizem que sao
# dela. `docker`, `php`, `git`, `gunzip` e `nano` sao dubles (o `git clone`
# copia um repositorio de mentira; o `docker` e o `php` so anotam onde
# rodaram), e os roteiros de `scripts/` que o bloco chama tambem anotam. O
# bloco entra pelo `.`, no mesmo shell, como quem cola no terminal: o `exit` ou
# o `set -e` fora do subshell fechariam o terminal, e isso tambem reprova. Tres
# casos por bloco:
#
#   sem o clone     o `~/franquiabv-lab` nao existe, e o `git clone` falha (a
#                   chave, a rede): NADA roda, e o clone da homologacao fica
#                   como estava
#   .env errado     o clone existe com o `.env` da homologacao: NADA roda, a
#                   saida diz PARE, e nenhum dos dois clones muda
#   certo           o clone com o `.env` do `.env.laboratorio.example`: o bloco
#                   roda ate o fim, tudo o que rodou rodou DENTRO dele, e o da
#                   homologacao fica como estava. No bloco do clone, o `.env` e
#                   o `local.php` novos sao os dos modelos.
#
# O QUE ELE NAO AFIRMA: que os comandos de dentro do bloco fazem o que a secao
# diz (os dubles nao sobem conteiner nenhum), nem nada do BVIP -- nada disto
# rodou la.

set -u

cd "$(dirname "$0")/.." || exit 2

DOC="${1:-docs/ambiente-homologacao.md}"
MODELO=.env.laboratorio.example
[ -r "$DOC" ] || { echo "NAO CONSEGUI MEDIR: nao li $DOC" >&2; exit 2; }
[ -r "$MODELO" ] || { echo "NAO CONSEGUI MEDIR: nao li $MODELO" >&2; exit 2; }
command -v awk > /dev/null 2>&1 || { echo "NAO CONSEGUI MEDIR: sem awk" >&2; exit 2; }

BASE=$(mktemp -d 2>/dev/null) || { echo "NAO CONSEGUI MEDIR: mktemp -d falhou" >&2; exit 2; }
trap 'rm -rf "$BASE"' EXIT INT TERM
BASE=$(cd "$BASE" && pwd -P)

# Os blocos `bash` da secao, um arquivo cada, na ordem.
mkdir -p "$BASE/blocos"
awk -v dir="$BASE/blocos" '
    /^## Laborat/ && /\(Fase 1\)$/ { dentro = 1; next }
    dentro && /^## / { exit }
    dentro && /^```bash$/ { codigo = 1; n++; arquivo = sprintf("%s/%02d.sh", dir, n); printf "" > arquivo; next }
    dentro && codigo && /^```$/ { codigo = 0; close(arquivo); next }
    dentro && codigo { print > arquivo }
' "$DOC"

# Os que agem: fora de comentario, um docker compose, um cp, um git clone, um
# gunzip ou um roteiro de scripts/.
age() {
    awk '{ sub(/^[ \t]*#.*$/, ""); sub(/[ \t]#.*$/, ""); print }' "$1" \
        | grep -Eq '(^|[[:space:];&|(])(docker[[:space:]]+compose|cp[[:space:]]|git[[:space:]]+clone|gunzip)|scripts/'
}
agem=''
for b in "$BASE"/blocos/*.sh; do
    [ -f "$b" ] || continue
    age "$b" && agem="$agem $b"
done
[ -n "$agem" ] || { echo "NAO CONSEGUI MEDIR: nenhum bloco bash que age na secao do laboratorio de $DOC" >&2; exit 2; }
juntos=$(cat $agem)
for marca in 'cp .env.laboratorio.example .env' ' up ' 'scripts/migrar-dados.sh' 'local.postgres.php.dist config/autoload/local.php'; do
    case $juntos in
        *"$marca"*) ;;
        *) echo "NAO CONSEGUI MEDIR: nenhum bloco da secao do laboratorio de $DOC tem \"$marca\" -- o ensaio nao cobriria o bloco que importa" >&2; exit 2 ;;
    esac
done

# O repositorio de mentira: o que os blocos copiam, com conteudo que diz o que
# e, e os roteiros de scripts/ que eles citam -- os .sh anotam onde rodaram.
R="$BASE/repositorio"
mkdir -p "$R/docker/config" "$R/config/autoload" "$R/postgres" "$R/scripts"
cp "$MODELO" "$R/.env.laboratorio.example"
echo 'MODELO DOCKER' > "$R/docker/config/local.php.docker"
echo 'MODELO POSTGRES' > "$R/config/autoload/local.postgres.php.dist"
for s in $(cat $agem | grep -Eo 'scripts/[A-Za-z0-9._-]+' | sort -u); do
    case $s in
        *.sh) printf '#!/bin/sh\necho "$(pwd -P)|sh %s" >> "$CHAMADAS"\n' "$s" > "$R/$s" ;;
        *) : > "$R/$s" ;;
    esac
done

# Os dubles.
mkdir -p "$BASE/bin"
for p in docker php; do
    printf '#!/bin/sh\necho "$(pwd -P)|%s $*" >> "$CHAMADAS"\nexit 0\n' "$p" > "$BASE/bin/$p"
done
printf '#!/bin/sh\nexit 0\n' > "$BASE/bin/gunzip"
printf '#!/bin/sh\nexit 0\n' > "$BASE/bin/nano"
cat > "$BASE/bin/git" <<'FIM'
#!/bin/sh
# git clone <url> <destino>: copia o repositorio de mentira; falha se o destino
# ja existe (como o git) ou se o caso pede (a chave, a rede).
[ "$1" = clone ] || exit 1
eval "destino=\${$#}"
[ -e "$destino" ] && { echo "fatal: destination path '$destino' already exists" >&2; exit 128; }
[ -n "${CLONE_FALHA:-}" ] && { echo "fatal: Could not read from remote repository." >&2; exit 128; }
mkdir -p "$destino" && cp -R "$REPOSITORIO/." "$destino/"
FIM
chmod +x "$BASE"/bin/* "$R"/scripts/*

# A impressao digital de um diretorio: cada arquivo e o seu cksum.
digital() { [ -d "$1" ] || { echo 'NAO EXISTE'; return; }; (cd "$1" && find . -type f | sort | while read -r f; do cksum "$f"; done); }

falhas=0
falhou() { echo "  - $1"; falhas=$((falhas + 1)); }

# caso <bloco> <nome> <estado do clone: nenhum, env-errado, certo> <o clone falha: sim/nao>
caso() {
    bloco="$1"; nome="$2"; estado="$3"; falha_clone="$4"
    c="$BASE/caso-$(basename "$bloco" .sh)-$nome"
    mkdir -p "$c/home"
    cp -R "$R" "$c/homologacao"
    echo 'COMPOSE_FILE=docker-compose.yml:docker-compose.homologacao.yml' > "$c/homologacao/.env"
    echo 'LOCAL DA HOMOLOGACAO' > "$c/homologacao/config/autoload/local.php"
    lab="$c/home/franquiabv-lab"
    case $estado in
        env-errado) cp -R "$R" "$lab"; cp "$c/homologacao/.env" "$lab/.env"; echo 'LOCAL DO LAB' > "$lab/config/autoload/local.php" ;;
        certo) cp -R "$R" "$lab"; cp "$MODELO" "$lab/.env"; echo 'LOCAL DO LAB' > "$lab/config/autoload/local.php" ;;
    esac
    : > "$c/chamadas.txt"
    homolog_antes=$(digital "$c/homologacao")
    lab_antes=$(digital "$lab")
    # O bloco entra no shell como quem cola no terminal: pelo `.`, no MESMO
    # shell. O `exit` ou o `set -e` fora do subshell fechariam o terminal de
    # quem cola -- e aqui a linha de depois nao sai.
    if [ "$falha_clone" = sim ]; then
        (cd "$c/homologacao" && HOME="$c/home" PATH="$BASE/bin:$PATH" CHAMADAS="$c/chamadas.txt" REPOSITORIO="$R" CLONE_FALHA=1 \
            sh -c '. "$1"; s=$?; echo "O TERMINAL FICOU"; exit $s' sh "$bloco") > "$c/saida.txt" 2>&1
    else
        (cd "$c/homologacao" && HOME="$c/home" PATH="$BASE/bin:$PATH" CHAMADAS="$c/chamadas.txt" REPOSITORIO="$R" \
            sh -c '. "$1"; s=$?; echo "O TERMINAL FICOU"; exit $s' sh "$bloco") > "$c/saida.txt" 2>&1
    fi
    codigo=$?
    rotulo="o bloco $(basename "$bloco" .sh) ($(grep -Ev '^[[:space:]]*(\(|\)|set -e|cd |grep -qx|#|$)' "$bloco" | head -1 | cut -c1-60)...), $nome"
    grep -qx 'O TERMINAL FICOU' "$c/saida.txt" || falhou "$rotulo: fecharia o terminal de quem cola o bloco (um exit ou um set -e fora do subshell)"
    [ "$(digital "$c/homologacao")" = "$homolog_antes" ] || falhou "$rotulo: MUDOU o clone da homologacao"
    case $estado in
        nenhum|env-errado)
            # O codigo de saida do bloco nao diz nada aqui: o do clone termina no
            # `nano`, fora do subshell, de proposito. O que diz e o que rodou.
            [ -s "$c/chamadas.txt" ] && falhou "$rotulo: RODOU fora do clone do laboratorio -- $(head -1 "$c/chamadas.txt" | sed "s|$c|<caso>|")"
            ;;
    esac
    case $estado in
        nenhum) [ -e "$lab" ] && falhou "$rotulo: criou $lab sem o git clone" ;;
        env-errado)
            [ "$(digital "$lab")" = "$lab_antes" ] || falhou "$rotulo: MUDOU o clone do laboratorio com o .env errado"
            if ! grep -q 'git clone' "$bloco"; then
                grep -q 'PARE' "$c/saida.txt" || falhou "$rotulo: a saida nao diz PARE"
            fi
            ;;
        certo|novo)
            [ "$codigo" = 0 ] || falhou "$rotulo: saiu com $codigo ($(tail -1 "$c/saida.txt"))"
            dentro=$(cd "$lab" 2>/dev/null && pwd -P)
            if [ -z "$dentro" ]; then
                falhou "$rotulo: o clone do laboratorio nao existe depois do bloco"
            elif grep -vq "^$dentro|" "$c/chamadas.txt"; then
                falhou "$rotulo: rodou fora do clone do laboratorio -- $(grep -v "^$dentro|" "$c/chamadas.txt" | head -1 | sed "s|$c|<caso>|")"
            fi
            ;;
    esac
    case $estado in
        novo)
            [ "$(cksum < "$lab/.env" 2>/dev/null)" = "$(cksum < "$MODELO")" ] || falhou "$rotulo: o .env do clone novo nao e o $MODELO"
            [ "$(cat "$lab/config/autoload/local.php" 2>/dev/null)" = 'MODELO DOCKER' ] || falhou "$rotulo: o local.php do clone novo nao e o docker/config/local.php.docker"
            ;;
        certo)
            if grep -Eq 'docker[[:space:]]+compose|scripts/' "$bloco"; then
                [ -s "$c/chamadas.txt" ] || falhou "$rotulo: nada rodou no clone certo -- a conferencia barra tambem o laboratorio"
            fi
            ;;
    esac
}

n=0
for b in $agem; do
    n=$((n + 1))
    if grep -q 'git clone' "$b"; then
        caso "$b" sem-o-clone nenhum sim
        caso "$b" env-errado env-errado nao
        caso "$b" certo novo nao
    else
        caso "$b" sem-o-clone nenhum nao
        caso "$b" env-errado env-errado nao
        caso "$b" certo certo nao
    fi
done

if [ "$falhas" -gt 0 ]; then
    echo "OS BLOCOS DO LABORATORIO AGEM FORA DO CLONE DELE ($DOC): $falhas caso(s)"
    exit 1
fi
echo "ok: os $n blocos do laboratorio que agem param sem o clone e com o .env errado, e com o certo rodam so dentro dele"
exit 0
