-- ---------------------------------------------------------------------------
-- Corrige os valores que o PostgreSQL REJEITA, antes da migração (F1.3).
--
--   docker compose exec -T mysql mysql -uroot -proot franquiabv_dev \
--     < scripts/pre-migracao-limpeza.sql
--
-- Sem isto a carga no PostgreSQL falha no meio, com a tabela pela metade.
--
-- São 2.416 linhas em 6 colunas, com anos como 0202, 0205, 0021, 0001 e 0000 em
-- datas cujo dia e mês costumam estar corretos. O MySQL aceita; o PostgreSQL não
-- tem ano 0 e recusa a carga.
--
-- ATENÇÃO AO HISTÓRICO: até 26/08/2026 este script cobria 19 linhas em 4 colunas,
-- e parecia completo. As outras 2.397 estão em `clientes.data_nascimento` e
-- `usuarios.data_nascimento`, e passaram despercebidas porque **a anonimização
-- reescreve essas colunas** — na base de desenvolvimento o defeito não existe.
--
-- A lição, que vale além deste arquivo: procurar coluna por coluna encontra o
-- que já se sabe. `scripts/medir-datas-invalidas.sql` varre o catálogo inteiro e
-- foi assim que as duas apareceram. Rode-o na réplica antes do corte.
--
-- IDEMPOTENTE: só toca linhas com ano inválido. Rodar de novo não faz nada.
--
-- ATENÇÃO: isto altera dados reais. Rode primeiro no ambiente com a base
-- anonimizada, confira a contagem, e só então aplique em produção — antes do
-- dump que alimenta a migração.
-- ---------------------------------------------------------------------------

SELECT '--- ANTES ---' AS '';
SELECT 'agendas.data'                    AS coluna, COUNT(*) AS invalidas FROM agendas             WHERE data        < '1000-01-01'
UNION ALL SELECT 'agendas_fechamentos.data_inicio', COUNT(*) FROM agendas_fechamentos WHERE data_inicio < '1000-01-01'
UNION ALL SELECT 'agendas_fechamentos.data_fim',    COUNT(*) FROM agendas_fechamentos WHERE data_fim    < '1000-01-01'
UNION ALL SELECT 'usuarios.data_contratacao',       COUNT(*) FROM usuarios            WHERE data_contratacao < '1000-01-01'
UNION ALL SELECT 'usuarios.data_nascimento',        COUNT(*) FROM usuarios            WHERE data_nascimento  < '1000-01-01'
UNION ALL SELECT 'clientes.data_nascimento',        COUNT(*) FROM clientes            WHERE data_nascimento  < '1000-01-01'
UNION ALL SELECT 'royalties (unidade,data) duplicados', COUNT(*) FROM (
    SELECT unidade FROM royalties GROUP BY unidade, data HAVING COUNT(*) > 1
) r;

START TRANSACTION;

-- 1. agendas.data — NOT NULL, então precisa de conserto, não de nulo.
--    O ano vem de data_criacao: as 7 linhas foram criadas em 2024-07-19 e o
--    agendamento é para 07-19, mesmo dia. Dia, mês e hora ficam intactos.
UPDATE agendas
   SET data = STR_TO_DATE(
           CONCAT(YEAR(data_criacao), DATE_FORMAT(data, '-%m-%d %H:%i:%s')),
           '%Y-%m-%d %H:%i:%s')
 WHERE data < '1000-01-01';

-- 2. agendas_fechamentos — as duas colunas são NOT NULL.
--    Quando só uma quebrou, o ano vem da irmã, que descreve o mesmo evento.
UPDATE agendas_fechamentos
   SET data_fim = STR_TO_DATE(
           CONCAT(YEAR(data_inicio), DATE_FORMAT(data_fim, '-%m-%d %H:%i:%s')),
           '%Y-%m-%d %H:%i:%s')
 WHERE data_fim < '1000-01-01' AND data_inicio >= '1000-01-01';

UPDATE agendas_fechamentos
   SET data_inicio = STR_TO_DATE(
           CONCAT(YEAR(data_fim), DATE_FORMAT(data_inicio, '-%m-%d %H:%i:%s')),
           '%Y-%m-%d %H:%i:%s')
 WHERE data_inicio < '1000-01-01' AND data_fim >= '1000-01-01';

--    Quando as duas quebraram, sobra data_criacao como fonte do ano.
UPDATE agendas_fechamentos
   SET data_inicio = STR_TO_DATE(CONCAT(YEAR(data_criacao), DATE_FORMAT(data_inicio, '-%m-%d %H:%i:%s')), '%Y-%m-%d %H:%i:%s'),
       data_fim    = STR_TO_DATE(CONCAT(YEAR(data_criacao), DATE_FORMAT(data_fim,    '-%m-%d %H:%i:%s')), '%Y-%m-%d %H:%i:%s')
 WHERE data_inicio < '1000-01-01' AND data_fim < '1000-01-01';

-- 3. usuarios.data_contratacao — ACEITA NULO, e não há fonte confiável para o
--    ano. São 5 colaboradores inativos, quatro com '0000-11-30' (artefato de
--    conversão do MySQL, sem informação nenhuma) e um com '0021-03-12'.
--
--    Escolha deliberada: NULO em vez de adivinhar. "Não sei quando foi
--    contratado" é verdade; "foi contratado em 2021" seria invenção. Se a
--    contratação real for conhecida, corrija manualmente ANTES de rodar isto.
UPDATE usuarios
   SET data_contratacao = NULL
 WHERE data_contratacao < '1000-01-01';

-- 4. As datas de NASCIMENTO inválidas, em `clientes` e `usuarios`.
--
--    Mesma regra do item 3, e pelo mesmo motivo: as duas colunas aceitam nulo, o
--    código já filtra por `IS NOT NULL`, e não há fonte confiável para o ano.
--    "Não sei quando nasceu" é verdade; "nasceu em 2000" seria invenção — e
--    invenção aqui manda parabéns no dia errado, que é pior que não mandar.
--
--    São 2.395 clientes e 2 colaboradores. O dia e o mês costumam estar
--    corretos, mas guardá-los sem ano exigiria coluna nova; não é decisão para
--    um script de limpeza.
UPDATE clientes
   SET data_nascimento = NULL
 WHERE data_nascimento < '1000-01-01';

UPDATE usuarios
   SET data_nascimento = NULL
 WHERE data_nascimento < '1000-01-01';

COMMIT;

-- ---------------------------------------------------------------------------
-- ---------------------------------------------------------------------------
-- 5. A duplicata de privilegio.
--
--    Uma unica linha repetida em 140 registros, com valores IDENTICOS: grupo 3
--    (Gerente unidade), funcionalidade 39 (Yungas), ler e escrever ligados, nos
--    ids 71 e 105.
--
--    Existia por isso um `GROUP BY fun.id` em PrivilegioRepository, so para a
--    tela de permissoes nao mostrar a linha duas vezes. Com a duplicata fora, o
--    agrupamento vira trivial e nao precisa escolher nada.
--
--    Aprovado pelo responsavel em 26/08/2026.
--
--    IDEMPOTENTE: numa base ja limpa, apaga zero linhas. A condicao e por
--    CONTEUDO, nao por id, para valer em qualquer base.
--
--    E O DE VALORES DIFERENTES TAMBEM SAI, FICANDO O MAIS ANTIGO (o menor id).
--    DECIDIDO PELO DONO EM 17/10/2026 (pergunta 237 da pagina do lote, a opcao
--    (c), "Fica o mais antigo"; o D374): "como a limpeza fazia ate hoje", e a
--    noite nao para. Entre 17 e 18/10/2026 este bloco so tirava o repetido de
--    valores iguais (a verificacao da fatia PRIVILEGIOS-GEMEOS), e o de valores
--    DIFERENTES -- que o "Novo" do codigo antigo ainda aceita calado ate a etapa
--    1 -- ficava para o dono decidir, e o passo 3 parava na chave do molde, na
--    migracao seguinte (`migracao-privilegios-unicos.sql`). A resposta voltou a
--    regra de antes: um molde so por (grupo, funcionalidade), o mais antigo.
--
--    O QUE MUDA E PARA QUEM ENTRAR NO GRUPO DEPOIS do corte -- cadastrado,
--    trocado para ele ou reativado: recebe o molde que ficou, que pode dar menos,
--    ou mais, do que as duas linhas somadas davam (hoje ele recebe as duas, e o
--    `Acl` as soma). Quem ja esta no grupo nao muda: as linhas das pessoas sao
--    `privilegios_usuarios`, e este bloco nao as toca.
--
--    A LISTA DE ANTES diz cada molde repetido de valores diferentes -- o grupo, a
--    funcionalidade, o que fica e os que saem, em id:ler escrever --, para o
--    registro da janela; as linhas que saem ficam no dump de antes dela. Na copia
--    de 16/08/2026, nenhum. O de valores iguais nao precisa de lista: sair
--    qualquer um dos dois nao muda nada.
-- ---------------------------------------------------------------------------

SELECT '--- privilegios duplicados: ANTES ---' AS '';
SELECT COUNT(*) AS grupos_duplicados FROM (
    SELECT grupo FROM privilegios GROUP BY grupo, funcionalidade HAVING COUNT(*) > 1
) x;

SELECT '--- privilegios duplicados de valores diferentes: grupo, funcionalidade, o que fica e os que saem (id:ler escrever) -- fica o mais antigo ---' AS '';
SELECT d.grupo, d.funcionalidade,
       (SELECT CONCAT(f.id, ':', f.ler, f.escrever) FROM privilegios f WHERE f.id = d.fica) AS fica,
       (SELECT GROUP_CONCAT(CONCAT(s.id, ':', s.ler, s.escrever) ORDER BY s.id)
          FROM privilegios s
         WHERE s.grupo = d.grupo AND s.funcionalidade = d.funcionalidade AND s.id <> d.fica) AS saem
  FROM (
    SELECT grupo, funcionalidade, MIN(id) AS fica
      FROM privilegios
     GROUP BY grupo, funcionalidade
    HAVING COUNT(*) > 1
       AND (MIN(ler) <> MAX(ler) OR MIN(escrever) <> MAX(escrever))
  ) d
 ORDER BY d.grupo, d.funcionalidade;

DELETE p FROM privilegios p
  JOIN (
    SELECT grupo, funcionalidade, MIN(id) AS fica
      FROM privilegios
     GROUP BY grupo, funcionalidade
    HAVING COUNT(*) > 1
  ) d ON d.grupo = p.grupo AND d.funcionalidade = p.funcionalidade
 WHERE p.id <> d.fica;

SELECT '--- privilegios duplicados: DEPOIS (tem que ser zero) ---' AS '';
SELECT COUNT(*) AS grupos_duplicados FROM (
    SELECT grupo FROM privilegios GROUP BY grupo, funcionalidade HAVING COUNT(*) > 1
) x;

-- ---------------------------------------------------------------------------
-- 6. As linhas duplicadas do dashboard de colaboradores (D40).
--
--    DEPOIS do COMMIT porque CREATE TEMPORARY TABLE é DDL e provoca commit
--    implícito no MySQL: dentro da transação acima, quebraria a atomicidade dos
--    UPDATEs de data.
--
--    O QUE ACONTECEU: a geração faz ler-e-criar-se-não-existe sem atomicidade, e
--    duas execuções simultâneas do cron criam duas linhas. A partir daí
--    `selecionarPorMesAnoColaborador` devolve sempre a mesma das duas, e a outra
--    CONGELA no valor do dia em que nasceu. Não são dois números concorrentes:
--    um é o retrato do primeiro dia, esquecido.
--
--    A REGRA, decidida em 26/08/2026:
--
--      Fica a linha que vinha sendo atualizada — `data_alteracao` mais recente.
--      Quando nenhuma foi atualizada (não há dado que distinga), fica a de menor
--      id, que é justamente a que a aplicação já lia.
--
--      A sobrevivente HERDA a `data_criacao` mais antiga do grupo, para o
--      registro guardar quando aquele mês começou a ser medido, e não quando a
--      duplicata nasceu.
--
--    MEDIDO NA BASE DE 26/08/2026: 107 grupos, todos de exatamente duas linhas.
--    Em 105 há uma única atualizada. Nos 2 restantes as duas linhas são
--    IDÊNTICAS — mesmos valores, mesma data — então apagar qualquer uma é
--    inócuo. Nenhum grupo mistura unidades.
--
--    ATENÇÃO: nos pares em que o relatório hoje mostra a linha congelada, o
--    número exibido MUDA depois desta limpeza. É correção, não regressão, mas
--    avise quem lê o relatório antes de aplicar.
--
--    IDEMPOTENTE: numa base já limpa, toda posição é 1 e os dois comandos
--    afetam zero linhas.
-- ---------------------------------------------------------------------------

SELECT '--- dashboard: ANTES ---' AS '';
SELECT COUNT(*) AS grupos_duplicados FROM (
    SELECT colaborador FROM dashboard_colaboradores
     GROUP BY colaborador, unidade, mes, ano HAVING COUNT(*) > 1
) x;

DROP TEMPORARY TABLE IF EXISTS _dashboard_ordem;

CREATE TEMPORARY TABLE _dashboard_ordem AS
SELECT id,
       ROW_NUMBER() OVER (
           PARTITION BY colaborador, unidade, mes, ano
           -- `data_alteracao IS NULL` ordena falso antes de verdadeiro: as
           -- atualizadas vêm primeiro, a mais recente à frente. O id desempata,
           -- e o menor é o que a aplicação já lia.
           ORDER BY (data_alteracao IS NULL), data_alteracao DESC, id
       ) AS posicao,
       MIN(data_criacao) OVER (
           PARTITION BY colaborador, unidade, mes, ano
       ) AS nascimento
  FROM dashboard_colaboradores;

-- A sobrevivente herda a data de criação mais antiga do grupo.
UPDATE dashboard_colaboradores d
  JOIN _dashboard_ordem o ON o.id = d.id AND o.posicao = 1
   SET d.data_criacao = o.nascimento
 WHERE d.data_criacao <> o.nascimento;

DELETE d FROM dashboard_colaboradores d
  JOIN _dashboard_ordem o ON o.id = d.id
 WHERE o.posicao > 1;

DROP TEMPORARY TABLE _dashboard_ordem;

SELECT '--- dashboard: DEPOIS (tem que ser zero) ---' AS '';
SELECT COUNT(*) AS grupos_duplicados FROM (
    SELECT colaborador FROM dashboard_colaboradores
     GROUP BY colaborador, unidade, mes, ano HAVING COUNT(*) > 1
) x;

-- ---------------------------------------------------------------------------
-- 7. A view órfã `v46` (D39).
--
--    DEPOIS do COMMIT de propósito: no MySQL, DDL provoca commit implícito e
--    não volta atrás num ROLLBACK. Misturar com os UPDATEs acima quebraria a
--    atomicidade deles.
--
--    Confirmado pelo responsável em 25/08/2026: sobra de deploy antigo, sem
--    consumidor. Foi por isso que a confirmação era necessária — nenhum arquivo
--    do repositório a menciona, mas o código não é a única coisa que fala com
--    este banco, e uma busca no projeto não encontraria uma ferramenta externa.
--
--    Ela só se revelou porque FALHA fora de produção: o DEFINER ('andre'@'%')
--    não existe em outro servidor, e o MySQL recusa antes de olhar a definição.
--    Em produção responde calada.
-- ---------------------------------------------------------------------------
DROP VIEW IF EXISTS `v46`;

-- ---------------------------------------------------------------------------
-- 8. As linhas duplicadas de royalties (D71).
--
--    DEPOIS do COMMIT pelo mesmo motivo do bloco 6.
--
--    O QUE ACONTECEU: nada impede duas linhas para o mesmo par (unidade, data),
--    e o `SUM` do relatorio soma as duas. Ele so acerta hoje POR ACIDENTE --
--    porque a duplicata e zerada --, e acidente nao e garantia.
--
--    MEDIDO EM 13/09/2026 na copia anonimizada de producao. A tabela responde
--    por producao: o anonimizador nao a toca, e ela esta completa (MAX(id)
--    32.580 contra AUTO_INCREMENT 32.581 no mysql.sql).
--
--      87 pares duplicados, 174 linhas, 29 unidades, de 2025-11-25 a 2025-12-14.
--      Nenhum grupo passa de DUAS linhas.
--
--      41 pares tem as DUAS linhas zeradas nas colunas somadas;
--      46 tem exatamente UMA com valor -- e em 46 de 46 o valor esta no MENOR
--      id, sem uma excecao;
--      ZERO tem as duas com valor.
--
--    A REGRA SE ESCOLHE SOZINHA: fica a de menor id. As 87 que saem sao todas
--    as 87 todo-zero.
--
--    POR ISSO A SOMA NAO MUDA, conferido e nao deduzido:
--      fat_total            57.632.640,83 -> 57.632.640,83
--      ret_total             2.422.062,28 ->  2.422.062,28
--
--    Nenhum numero de relatorio se mexe -- ao contrario do bloco 6, que precisa
--    avisar quem le que o numero exibido MUDA. Aqui nao ha o que avisar.
--
--    IDEMPOTENTE: numa base ja limpa o DELETE afeta zero linhas.
-- ---------------------------------------------------------------------------

SELECT '--- royalties: ANTES ---' AS '';
SELECT COUNT(*) AS pares_duplicados, SUM(n) AS linhas FROM (
    SELECT unidade, data, COUNT(*) AS n FROM royalties
     GROUP BY unidade, data HAVING COUNT(*) > 1
) x;

DELETE r FROM royalties r
  JOIN (
      SELECT unidade, data, MIN(id) AS fica
        FROM royalties
       GROUP BY unidade, data
      HAVING COUNT(*) > 1
  ) g ON g.unidade = r.unidade AND g.data = r.data
 WHERE r.id <> g.fica;

SELECT '--- royalties: DEPOIS (tem que ser zero) ---' AS '';
SELECT COUNT(*) AS pares_duplicados FROM (
    SELECT unidade FROM royalties GROUP BY unidade, data HAVING COUNT(*) > 1
) x;

SELECT '--- DEPOIS (tem que ser tudo zero) ---' AS '';
SELECT 'agendas.data'                    AS coluna, COUNT(*) AS invalidas FROM agendas             WHERE data        < '1000-01-01'
UNION ALL SELECT 'agendas_fechamentos.data_inicio', COUNT(*) FROM agendas_fechamentos WHERE data_inicio < '1000-01-01'
UNION ALL SELECT 'agendas_fechamentos.data_fim',    COUNT(*) FROM agendas_fechamentos WHERE data_fim    < '1000-01-01'
UNION ALL SELECT 'usuarios.data_contratacao',       COUNT(*) FROM usuarios            WHERE data_contratacao < '1000-01-01'
UNION ALL SELECT 'usuarios.data_nascimento',        COUNT(*) FROM usuarios            WHERE data_nascimento  < '1000-01-01'
UNION ALL SELECT 'clientes.data_nascimento',        COUNT(*) FROM clientes            WHERE data_nascimento  < '1000-01-01'
UNION ALL SELECT 'royalties (unidade,data) duplicados', COUNT(*) FROM (
    SELECT unidade FROM royalties GROUP BY unidade, data HAVING COUNT(*) > 1
) r;
