#!/usr/bin/env bash
#
# Monta um PostgreSQL limpo, entra no ERP e pede todas as telas do menu.
#
#     sh scripts/medir-telas-no-postgres.sh            # PostgreSQL
#     sh scripts/medir-telas-no-postgres.sh --mysql    # o mesmo, contra MySQL
#
# POR QUE ISTO EXISTE (D97). O D96 mostrou que o login do ERP nao sobrevivia ao
# PostgreSQL, e que nenhuma suite abria uma tela. A pergunta seguinte era obvia:
# quantas telas mais quebram? A resposta, na primeira execucao, foi NOVE -- e
# ZERO no MySQL.
#
# O `--mysql` existe por causa dessa segunda metade. Sem o controle, "nove telas
# quebradas" nao diz se o defeito e da migracao ou do cenario de fixtures.
#
# ---------------------------------------------------------------------------
# ELE CONCEDE PRIVILEGIOS, e isso precisa ser dito.
#
# As fixtures criam o usuario de teste SEM poder nenhum, de proposito -- o
# proprio `fixtures.sql` explica que nao se da poder a usuario de fixture por
# acidente. Mas tela que o ACL nega responde 404, e uma medicao de telas que so
# alcanca as negadas mede permissao, nao tela: a primeira execucao visitou 61
# enderecos e 57 eram 404.
#
# A concessao fica AQUI, no banco descartavel que este roteiro acabou de montar,
# e nao nas fixtures. Assim a suite de contrato continua rodando com um usuario
# sem poderes, e a medicao enxerga o ERP inteiro.

set -euo pipefail

MYSQL=""
[ "${1:-}" = "--mysql" ] && MYSQL="1"

LOCAL="config/autoload/local.php"
BACKUP="$(mktemp)"
BANCO=$([ -n "$MYSQL" ] && echo "franquiabv_contrato" || echo "franquiabv_pgcontrato")

# A CONCESSAO E REPETIVEL (07/11/2026, a fatia 102, D187): as fixtures ja dao ao
# gerente de fixture dez destas funcionalidades, e as duas copias do esquema tem a
# unicidade do par (no MySQL, `uq_privilegios_usuarios_usuario_funcionalidade`; no
# PostgreSQL, com o `inquilino_id`, desde 17/10/2026). Sem o desvio o INSERT batia
# na chave: no PostgreSQL abortava o roteiro; no MySQL o `|| true` engolia, e o
# MySQL era medido so com as dez. Ela vale duas vezes -- antes das telas e antes
# dos relatorios --, e o `ConcessaoDoUsuarioDeFixtureTest` roda os dois textos
# (nesta ordem: o do MySQL, o do PostgreSQL) contra as fixtures.
CONCEDER_MYSQL="INSERT INTO privilegios_usuarios (usuario, funcionalidade, ler, escrever)
    SELECT 90001001, f.id, 1, 1 FROM funcionalidades f
     WHERE f.id >= 90002000
       AND NOT EXISTS (SELECT 1 FROM privilegios_usuarios p
                        WHERE p.usuario = 90001001 AND p.funcionalidade = f.id);"
CONCEDER_PG="SET app.inquilino_id = 1;
    INSERT INTO privilegios_usuarios (usuario, funcionalidade, ler, escrever)
    SELECT 90001001, id, TRUE, TRUE FROM funcionalidades WHERE id >= 90002000
    ON CONFLICT (inquilino_id, usuario, funcionalidade) DO NOTHING;"

if [ ! -f "$LOCAL" ]; then
    echo "nao achei $LOCAL -- rode a partir da raiz do projeto." >&2
    exit 2
fi

if grep -q "'dbname' => '${BANCO}'" "$LOCAL"; then
    echo "O local.php JA APONTA para ${BANCO}." >&2
    echo "  Uma execucao anterior nao restaurou o ambiente. Aponte-o de volta antes." >&2
    exit 2
fi

cp "$LOCAL" "$BACKUP"

restaurar() {
    cp "$BACKUP" "$LOCAL"
    rm -f "$BACKUP"
    docker compose exec -T app sh -c 'rm -rf data/DoctrineORMModule/Proxy/* data/cache/*; true' >/dev/null 2>&1 || true
    echo
    echo "ambiente restaurado: $(grep -m1 dbname "$LOCAL" | tr -d ' ')"

    if grep -q "'dbname' => '${BANCO}'" "$LOCAL"; then
        echo "  ATENCAO: o local.php CONTINUA apontando para ${BANCO}." >&2
    fi
}
trap restaurar EXIT INT TERM

if [ -n "$MYSQL" ]; then
    # O BANCO DO CONTROLE E MONTADO DO ZERO, como o do PostgreSQL.
    #
    # Ate 05/09/2026 ele nao era: o roteiro assumia que `franquiabv_contrato`
    # ja existia e so acrescentava privilegios. O controle passava a comparar o
    # PostgreSQL de HOJE com um MySQL montado sabe-se la quando -- e as fixtures
    # usam `CURRENT_DATE`, entao o caixa do cenario nasce com a data da
    # montagem.
    #
    # Deu para ver: dos 31 relatorios, 28 saem com texto IDENTICO nos dois
    # bancos, e a unica diferenca de texto era `04/09/2026` contra
    # `05/09/2026`. Um dia a mais de idade aparecendo como divergencia entre
    # engines. E o D106 outra vez, um andar abaixo: comparacao so responde a
    # pergunta dela quando os dois lados tem a mesma idade.
    echo "montando ${BANCO} a partir de mysql.sql mais as fixtures..."

    docker compose exec -T mysql mysql -uroot -proot -e \
        "DROP DATABASE IF EXISTS ${BANCO}; CREATE DATABASE ${BANCO} DEFAULT CHARACTER SET utf8mb4;" \
        2>&1 | grep -v "Using a password" || true

    # A LINHA DO GTID SAI ANTES. O `mysql.sql` e dump de producao e traz
    # `SET @@GLOBAL.GTID_PURGED=...`, que este servidor recusa -- ele ja tem
    # GTIDs executados, e os conjuntos nao podem se sobrepor. No CI o servico
    # nasce limpo a cada execucao e a linha passa; aqui, nao.
    grep -v "GTID_PURGED" mysql.sql \
        | docker compose exec -T mysql mysql -uroot -proot "${BANCO}" 2>&1 \
        | grep -v "Using a password" || true

    docker compose exec -T mysql mysql -uroot -proot "${BANCO}" < tests/Caracterizacao/fixtures.sql 2>&1 \
        | grep -v "Using a password" || true

    # O MAIOR ID ANTES DA CONCESSAO: o que passar dele, a retirada tira depois das telas.
    ANTES=$(docker compose exec -T mysql mysql -uroot -proot "${BANCO}" -N -e \
        "SELECT COALESCE(MAX(id), 0) FROM privilegios_usuarios" 2>/dev/null | tr -d '\r')
    docker compose exec -T mysql mysql -uroot -proot "${BANCO}" -e "${CONCEDER_MYSQL}" \
        2>&1 | grep -v "Using a password" || true

    sed -i "s/'dbname' => '[a-z_]*'/'dbname' => '${BANCO}'/" "$LOCAL"
else
    echo "montando ${BANCO} a partir de postgres/schema.sql mais as fixtures..."

    docker compose exec -T postgres psql -U franquiabv -d postgres -q \
        -c "DROP DATABASE IF EXISTS ${BANCO};" -c "CREATE DATABASE ${BANCO};" >/dev/null

    docker compose exec -T postgres psql -U franquiabv -d "${BANCO}" -q -v ON_ERROR_STOP=1 -f - \
        < postgres/schema.sql >/dev/null

    {
        echo "SET app.inquilino_id = 1;"
        grep -v "^SET NAMES" tests/Caracterizacao/fixtures.sql
    } | docker compose exec -T postgres psql -U franquiabv -d "${BANCO}" -q -v ON_ERROR_STOP=1 -f -

    # AS SEQUENCIAS PRECISAM SER AVANCADAS DEPOIS DAS FIXTURES.
    #
    # `fixtures.sql` grava com id explicito, e no PostgreSQL isso NAO move a
    # sequencia. A primeira insercao feita pela aplicacao pede o id 1, acha o
    # cliente avulso no lugar e responde 500 -- foi o que o cadastro da quarta
    # fatia encontrou. O MySQL nao tem o problema: o AUTO_INCREMENT sobe
    # sozinho quando alguem grava um id maior.
    docker compose exec -T postgres psql -U franquiabv -d "${BANCO}" -q -v ON_ERROR_STOP=1 -f - \
        < postgres/repontar-sequencias.sql

    ANTES=$(docker compose exec -T postgres psql -U franquiabv -d "${BANCO}" -qAt -c \
        "SELECT COALESCE(MAX(id), 0) FROM privilegios_usuarios")
    docker compose exec -T postgres psql -U franquiabv -d "${BANCO}" -q -v ON_ERROR_STOP=1 -c "${CONCEDER_PG}"

    # COMO O CI CONECTA: pelo DONO do banco, e nao por `bvip_app`.
    #
    # O dist aponta para `bvip_app`, que tem RLS ativo -- e sob RLS a aplicacao
    # so enxerga o inquilino declarado. O job do CI usa o dono, que ignora RLS,
    # porque a pergunta dele e "o codigo roda no PostgreSQL?"; quem pergunta
    # "o isolamento vale?" e o job do schema, com `postgres/teste-rls.sql`.
    #
    # Usar o mesmo usuario do CI alinha o que se mede -- e NAO era ele a causa
    # da tela que passava aqui e falhava la. A causa apareceu depois: o
    # `display_errors` deste ambiente fazia o aviso sair antes da resposta, o
    # cabecalho ia com 200, e o medidor -- que olhava so o status -- dava a tela
    # por boa. Hoje ele le o corpo tambem (D97).
    sed -e "s/'dbname' *=> *'[a-z_]*'/'dbname' => '${BANCO}'/" \
        -e "s/'user' *=> *'bvip_app'/'user' => 'franquiabv'/" \
        config/autoload/local.postgres.php.dist > "$LOCAL"
fi

# O TOKEN DAS ROTINAS, sorteado e so desta corrida (03/10/2026, revisao do
# SEGREDOS). Ate entao o medidor das rotinas o lia do `CronJobController`; o
# literal saiu do codigo, e nenhum dos dois `local.php` acima o tem -- sem
# isto, o medidor sai com 2 e o `set -e` derruba a corrida antes de `/adm/api`
# e dos relatorios. O `trap` devolve o `local.php` de antes, sem o token.
sh scripts/sortear-token-cron.sh "$LOCAL"
docker compose exec -T app php -l config/autoload/local.php

docker compose exec -T app sh -c 'rm -rf data/DoctrineORMModule/Proxy/* data/cache/*; true'

# O OPCACHE MEDE O PASSADO: o php-fpm ainda serve o `local.php` de antes por
# ate ~3 s depois da troca, e o primeiro arquivo da suite ia ao banco velho
# (o vermelho do aparelho, nas fatias 76d e 81). Ver `esperar-o-opcache.sh`.
sh scripts/esperar-o-opcache.sh

# AS TRAVAS DE EXECUCAO SAIEM ANTES DA MEDICAO.
#
# `TravaDeExecucao` guarda um arquivo em /tmp, e quem o cria vira dono. Uma
# execucao pela linha de comando (root) deixa o arquivo com dono errado, e a
# chamada seguinte pela WEB (www-data) nao consegue abri-lo -- a rotina morre
# com RuntimeException e a resposta continua 200 (D98).
#
# Aqui a pergunta e sobre o BANCO, e trava velha de outra execucao seria
# ruido. O defeito em si esta registrado, medido e nao apagado.
docker compose exec -T app sh -c 'rm -f /tmp/*.lock; true'
docker compose exec -T app php scripts/definir-senha-contrato.php >/dev/null

echo
docker compose exec -T -e DESPEJO app php scripts/medir-telas-no-postgres.php http://nginx

# A CONCESSAO SAI DEPOIS DAS TELAS (07/11/2026, a verificacao da fatia 102, D187),
# como no passo do `ci.yml`: os ensaios abaixo montam o proprio cenario de
# privilegio do mesmo gerente, e com todas as telas concedidas batiam na chave ou
# recusavam rodar. Saem as linhas dele acima do maior id de antes; as das
# fixtures ficam. Antes dos relatorios, a concessao volta.
test -n "${ANTES}"
if [ -n "$MYSQL" ]; then
    docker compose exec -T mysql mysql -uroot -proot "${BANCO}" -e \
        "DELETE FROM privilegios_usuarios WHERE usuario = 90001001 AND id > ${ANTES};" \
        2>&1 | grep -v "Using a password" || true
else
    docker compose exec -T postgres psql -U franquiabv -d "${BANCO}" -q -v ON_ERROR_STOP=1 -c \
        "SET app.inquilino_id = 1;
         DELETE FROM privilegios_usuarios WHERE usuario = 90001001 AND id > ${ANTES};"
fi

# E AS ROTINAS DE CRON, no mesmo banco e na mesma corrida.
#
# Elas sao o terceiro mundo do sistema -- nem tela nem API do aplicativo --
# e escrevem muito, que e onde os defeitos de tipo mordem. Montar o banco de
# novo so para elas seria repetir dois minutos de trabalho por nada.
echo
docker compose exec -T app php scripts/medir-cron-no-postgres.php http://nginx

# E OS ENDPOINTS DE `/adm/api`, o codigo NOVO.
#
# A fatia do PDV foi provada por curl a mao e por teste de caracterizacao;
# nenhuma das duas se repete a cada push. Nove dos onze endpoints escrevem,
# e por isso eles so podem ser chamados aqui: este banco nasceu ha dois
# minutos e morre no fim (D101).
echo
# O ENSAIO VEM ANTES DO MEDIDOR, e a ordem nao e arbitraria: o medidor escreve
# -- fecha o caixa da fixture, apaga o agendamento -- e o ensaio precisa do
# cenario como as fixtures o deixaram. Invertidos, o ensaio comecaria pedindo um
# caixa que o medidor acabou de fechar.
# E O ENSAIO DE PERMISSAO VEM ANTES DOS DOIS, porque ele nao escreve nada: as
# dez tentativas dele sao recusadas, e recusa nao deixa rastro no cenario. Rodar
# primeiro tambem responde cedo a pergunta mais barata -- se a API voltou a
# aceitar quem nao tem privilegio, o resto da medicao pode esperar (D123).
docker compose exec -T app php scripts/ensaiar-permissao-adm-api.php http://nginx

# AS CAMPANHAS DE CUPOM (28/09/2026): escreve na faixa 90007600-90007699 e desfaz
# tudo no `finally` -- o cenario das fixtures fica como estava para os de baixo.
docker compose exec -T app php scripts/ensaiar-cupons-adm-api.php http://nginx

# A FIDELIDADE DO CLIENTE (28/09/2026): escreve na faixa 90007800-90007899, e
# devolve o credito, o pacote e os caixas do gerente pelo valor lido no comeco.
docker compose exec -T app php scripts/ensaiar-fidelidade-adm-api.php http://nginx

# OS USUARIOS E A BARREIRA DE ORIGEM (29/09/2026): a faixa 90007950-90007959, desfeita
# no `finally`.
docker compose exec -T app php scripts/ensaiar-usuarios-adm-api.php http://nginx

# AS ETIQUETAS DOS SERVICOS (20/10/2026): a faixa 90009700-90009799, desfeita no `finally`, e
# a 90001700 da fixture devolvida pelo valor lido no comeco.
docker compose exec -T app php scripts/ensaiar-etiquetas-adm-api.php http://nginx

# OS BANNERS DO APLICATIVO (20/10/2026): a faixa 90009850-90009899 e os banners "Zzq...",
# desfeitos no `finally`, e os arquivos que o ensaio pos em `public/banners` apagados pelo nome.
docker compose exec -T app php scripts/ensaiar-banners-adm-api.php http://nginx

# OS SORTEIOS (21/10/2026): a faixa 90025501-90025599, o administrador 90025551 e o privilegio
# 90025552, desfeitos no `finally`; nenhum sorteio real e tocado.
docker compose exec -T app php scripts/ensaiar-sorteios-adm-api.php http://nginx

# CONTAS A PAGAR (04/11/2026, a fatia 77): a leitura e o "dar por quitada"; a faixa 90004700-90004799,
# o administrador 90004701, o leitor 90004703 e os privilegios 90004702 e 90004704, desfeitos no
# `finally`; as despesas 90001000 e 90001100 das fixtures so sao lidas, e conferidas no fim.
docker compose exec -T app php scripts/ensaiar-saidas-adm-api.php http://nginx

# A VIP CLASS DO ALUNO (05/11/2026, a fatia 80): o leitor 90080901, os privilegios 90080902 e 90080903, as
# conclusoes que a API grava e o fundo do certificado, desfeitos no `finally`; os cursos 90079001 a
# 90079003 da fixture so sao lidos, e conferidos no fim.
docker compose exec -T app php scripts/ensaiar-vipclass-adm-api.php http://nginx

# A ADMINISTRACAO DA VIP CLASS (05/11/2026, a fatia 82): o administrador 90082901 e o grupo dele, o privilegio
# 90082902 e os cursos "Ensaio 82", desfeitos no `finally`; os cursos 90079001 a 90079003 da fixture, conferidos no fim.
docker compose exec -T app php scripts/ensaiar-cursos-adm-api.php http://nginx

# A BIBLIOTECA DE ARQUIVOS (22/10/2026): o /arquivos/ fechado no nginx e a entrega com sessao; o
# privilegio 90025601 e os tres arquivos que o ensaio poe em `public/arquivos`, desfeitos no `finally`.
docker compose exec -T app php scripts/ensaiar-arquivos-adm-api.php http://nginx

# O WHATSAPP DA UNIDADE (23/10/2026, a fatia 31, WHATSAPP-CONEXAO): so recusas e os controles
# `desligado` e `sem_credencial`, que nao saem da maquina; recusa rodar se a unidade da sessao tiver
# chave (o W10). Os privilegios 90025701 e 90025702 e o `whatsapp_ativo` da 90001000, desfeitos no
# `finally`.
docker compose exec -T app php scripts/ensaiar-whatsapp-adm-api.php http://nginx

# O FLUXO INTEIRO DO WHATSAPP (24/10/2026, a fatia 33, WHATSAPP-PROVEDOR-DE-MENTIRA): contra o provedor de
# mentira, que o ensaio sobe no loopback do app e para no fim; recusa rodar se a URL configurada nao for
# do loopback. O privilegio 90025703, as colunas do WhatsApp da 90001000, o rastro, o provedor e o
# `whatsapp.local.php` copiado, desfeitos no `finally`.
docker compose exec -T app php scripts/ensaiar-whatsapp-provedor-de-mentira.php http://nginx

# A PESQUISA DA ADESAO (24/10/2026, a fatia 35, PESQUISAS-API): a faixa 90035900-90035999 (as
# pesquisas, o leitor 90035991 e os privilegios 90035992 e 90035993), desfeita no `finally`, e a
# adesao do banco devolvida pelo valor lido no comeco.
docker compose exec -T app php scripts/ensaiar-pesquisas-adm-api.php http://nginx

# OS AVISOS DO MURAL DA AGENDA (25/10/2026, a fatia 37, MENSAGENS-API): a faixa 90037900-90037999
# (os avisos, o administrador 90037901, o leitor 90037902, os grupos 90037900 e 90037905 e os
# privilegios 90037903 e 90037904), desfeita no `finally`. Nenhuma unidade muda de estado.
docker compose exec -T app php scripts/ensaiar-mensagens-adm-api.php http://nginx

# AS CAMPANHAS, AS ESCRITAS (26/10/2026, a fatia 92d, NOTIFICACOES-API-ESCRITA): o cadastro, a alteracao,
# a pausa, a retomada, o cancelamento e o "mandar para mim primeiro" contra o provedor de mentira, que o
# ensaio sobe no loopback e para no fim; recusa rodar se o endereco do teste nao for o dele. As campanhas,
# o privilegio 90092901, as colunas da unidade 90001000 e o telefone do gerente, desfeitos no `finally`.
docker compose exec -T app php scripts/ensaiar-notificacoes-adm-api.php http://nginx

docker compose exec -T app php scripts/ensaiar-fluxo-adm-api.php http://nginx

docker compose exec -T app php scripts/medir-adm-api-no-postgres.php http://nginx

# E OS RELATORIOS, que sao a consulta pesada do sistema.
#
# O medidor de telas alcanca a tela de FILTRO; a consulta roda quando alguem
# aperta "gerar". Agregacao com data e onde os dois bancos mais diferem, e ate
# aqui nenhum relatorio tinha sido pedido uma vez sequer (D104).
echo
# A CONCESSAO DE NOVO, para os relatorios: o gerente precisa delas para pedi-los.
if [ -n "$MYSQL" ]; then
    docker compose exec -T mysql mysql -uroot -proot "${BANCO}" -e "${CONCEDER_MYSQL}" \
        2>&1 | grep -v "Using a password" || true
else
    docker compose exec -T postgres psql -U franquiabv -d "${BANCO}" -q -v ON_ERROR_STOP=1 -c "${CONCEDER_PG}"
fi
docker compose exec -T -e DESPEJO app php scripts/medir-relatorios-no-postgres.php http://nginx
