#!/usr/bin/env python3
"""Documento comprobatorio dos ajustes do Relatorio de Bugs Monetarie (28 itens).

Regras do dono:
  - escrita humana objetiva, acentuacao pt-br perfeita, SEM travessao;
  - relatorio do cliente NUNCA expoe defeito interno (bug respondido como
    "corrigido e validado" com o estado ATUAL provado, sem causa raiz interna);
  - itens ainda abertos sao ditos "em desenvolvimento" com honestidade;
  - De: Vulci (equipe tecnica) Para: Monetarie (cliente).

Evidencias: capturas vivas do ambiente de homologacao (coreadmin-h) feitas em
20/07/2026, na mesma versao publicada em producao. Pasta ./evidencias.
"""
import os
import tempfile

from PIL import Image as PILImage
from reportlab.lib import colors
from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import ParagraphStyle, getSampleStyleSheet
from reportlab.lib.units import mm
from reportlab.platypus import (
    HRFlowable, Image, KeepTogether, Paragraph, SimpleDocTemplate, Spacer,
)

GOLD = colors.HexColor("#ffc847")
DARK = colors.HexColor("#101820")
GREEN = colors.HexColor("#1a7a3c")
AMBER = colors.HexColor("#a86500")
BLUE = colors.HexColor("#1f4e79")

HERE = os.path.dirname(os.path.abspath(__file__))
EV = os.path.join(HERE, "evidencias")
_tmp = []


def ss_styles():
    ss = getSampleStyleSheet()
    ss.add(ParagraphStyle("Titulo", fontSize=19, leading=24, textColor=DARK, fontName="Helvetica-Bold", spaceAfter=4))
    ss.add(ParagraphStyle("Meta", fontSize=10.5, leading=15, textColor=DARK))
    ss.add(ParagraphStyle("H1x", parent=ss["Heading1"], fontSize=13.5, leading=17, textColor=DARK, spaceBefore=14, spaceAfter=3))
    ss.add(ParagraphStyle("H2x", parent=ss["Heading2"], fontSize=11.5, leading=15, textColor=BLUE, spaceBefore=10, spaceAfter=2))
    ss.add(ParagraphStyle("Corpo", parent=ss["BodyText"], fontSize=10.5, leading=15.5, spaceAfter=6))
    ss.add(ParagraphStyle("ItemTit", fontSize=11, leading=15, textColor=DARK, fontName="Helvetica-Bold", spaceBefore=8, spaceAfter=2))
    ss.add(ParagraphStyle("Legenda", fontSize=8.5, leading=11, textColor=colors.HexColor("#555555"), spaceBefore=2, spaceAfter=12))
    return ss


STATUS_COLOR = {
    "Corrigido e validado": GREEN,
    "Corrigido, item complementar em avaliacao": AMBER,
    "Em desenvolvimento": BLUE,
}
STATUS_LABEL = {
    "Corrigido, item complementar em avaliacao": "Corrigido, item complementar em avaliação",
}


def status_html(s):
    c = STATUS_COLOR.get(s, DARK)
    return f'<font color="{c.hexval()}"><b>{STATUS_LABEL.get(s, s)}</b></font>'


def img_flowable(path, max_w=165 * mm, max_h=215 * mm):
    im = PILImage.open(path).convert("RGB")
    fd, tmp = tempfile.mkstemp(suffix=".jpg")
    os.close(fd)
    im.save(tmp, "JPEG", quality=80)
    _tmp.append(tmp)
    w, h = im.size
    scale = min(max_w / w, max_h / h, 1.0)
    return Image(tmp, width=w * scale, height=h * scale)


def ev(name):
    return os.path.join(EV, name)


# ---------------------------------------------------------------------------
# Conteudo: por tela, cada item = (label, status, texto)
# ---------------------------------------------------------------------------
SECOES = [
    {
        "heading": "1. Tesouraria &middot; Liquida&ccedil;&atilde;o",
        "img": ("CA-001-005-liquidacao.png", "Tela Liquida&ccedil;&atilde;o em opera&ccedil;&atilde;o: saldo da cabine PIX exibido, consolidado di&aacute;rio preenchido, status em portugu&ecirc;s e identificador BACEN com r&oacute;tulo claro."),
        "items": [
            ("CA-001 &nbsp;Indicador “Dispon&iacute;vel agora”", "Corrigido e validado",
             "O cart&atilde;o “Conta de Liquida&ccedil;&atilde;o (cabine PIX)” passou a exibir o saldo real da cabine. No ambiente atual mostra o valor de posi&ccedil;&atilde;o com a origem “pix_cabin:camt.053” e o hor&aacute;rio da &uacute;ltima atualiza&ccedil;&atilde;o, no lugar da mensagem “Indispon&iacute;vel”."),
            ("CA-002 &nbsp;Gr&aacute;fico “Hist&oacute;rico do saldo”", "Corrigido e validado",
             "O gr&aacute;fico passou a trabalhar sobre o saldo real da cabine. A escala do eixo agora reflete a posi&ccedil;&atilde;o efetiva (na casa de bilh&otilde;es), e cada nova captura registrada &eacute; plotada ao longo do tempo. Antes o eixo variava de R$ 0,00 a R$ 1,00 porque as capturas nasciam sem valor."),
            ("CA-003 &nbsp;Consolidado di&aacute;rio (Core)", "Corrigido e validado",
             "O bloco “Consolidado di&aacute;rio (Core)” passou a apresentar a tabela de movimentos por dia (data, quantidade, cr&eacute;dito, d&eacute;bito, l&iacute;quido e saldos), respeitando o per&iacute;odo filtrado. A mensagem “Sem consolidado para o per&iacute;odo” s&oacute; aparece quando de fato n&atilde;o h&aacute; movimento."),
            ("CA-004 &nbsp;Status dos movimentos em portugu&ecirc;s", "Corrigido e validado",
             "A coluna Status passou a exibir os r&oacute;tulos em portugu&ecirc;s: “Conclu&iacute;do”, “Liquidado”, “Rejeitado” e demais equivalentes, mantendo o valor t&eacute;cnico interno inalterado."),
            ("CA-005 &nbsp;R&oacute;tulo do Identificador BACEN", "Corrigido e validado",
             "O identificador passou a usar r&oacute;tulos claros: o PIX aparece com “PIX (E2E)” e a TED com “TED (STR)”, deixando expl&iacute;cito o trilho da transa&ccedil;&atilde;o."),
        ],
    },
    {
        "heading": "2. Tesouraria &middot; Relat&oacute;rio de Taxas",
        "img": ("CA-006-relatorio-taxas-vazio.png", "Grid de taxas com mensagem de estado vazio “Nenhuma tarifa cobrada no per&iacute;odo”."),
        "img2": ("CA-007-gerar-detalhe-pronto.png", "Gera&ccedil;&atilde;o do detalhe conclu&iacute;da: status “Pronto” e link “Baixar CSV” dispon&iacute;vel."),
        "items": [
            ("CA-006 &nbsp;Estado vazio do grid", "Corrigido e validado",
             "Quando n&atilde;o h&aacute; tarifas no per&iacute;odo, o grid passou a exibir a mensagem “Nenhuma tarifa cobrada no per&iacute;odo”, no padr&atilde;o das demais telas, em vez de ficar em branco sem explica&ccedil;&atilde;o."),
            ("CA-007 &nbsp;Gera&ccedil;&atilde;o do detalhe (CSV)", "Corrigido e validado",
             "O pedido “Gerar detalhe” passou a fechar o ciclo corretamente: evolui de “Processando” para “Pronto” e disponibiliza o link “Baixar CSV”, mesmo quando o per&iacute;odo n&atilde;o tem lan&ccedil;amentos. N&atilde;o fica mais preso em “Aguardando”."),
        ],
    },
    {
        "heading": "3. Tesouraria &middot; Reconcilia&ccedil;&atilde;o Cont&aacute;bil PIX",
        "img": ("CA-008-010-recon-contabil-pix.png", "Grid de diverg&ecirc;ncias com tipos em portugu&ecirc;s, coluna Data ordenavel e valores esperados preenchidos."),
        "items": [
            ("CA-008 &nbsp;Coluna “Tipo” traduzida", "Corrigido e validado",
             "A coluna Tipo e os chips de resumo passaram a exibir os r&oacute;tulos em portugu&ecirc;s: “E2E duplicado”, “Sem lan&ccedil;amento”, “Valor divergente”, mantendo o c&oacute;digo t&eacute;cnico interno."),
            ("CA-009 &nbsp;Completude da diverg&ecirc;ncia “E2E duplicado”", "Corrigido e validado",
             "As diverg&ecirc;ncias do tipo “E2E duplicado” passaram a trazer o valor esperado da transa&ccedil;&atilde;o e o detalhe explicativo (“E2E repetido no per&iacute;odo”). Nos casos em que a diverg&ecirc;ncia se refere a lan&ccedil;amentos sem transa&ccedil;&atilde;o correspondente, a dire&ccedil;&atilde;o segue como n&atilde;o aplic&aacute;vel, por defini&ccedil;&atilde;o da regra."),
            ("CA-010 &nbsp;Coluna de Data no grid", "Corrigido e validado",
             "O grid de diverg&ecirc;ncias passou a ter a coluna “Data”, orden&aacute;vel, permitindo identificar a que dia cada diverg&ecirc;ncia pertence e ordenar cronologicamente."),
        ],
    },
    {
        "heading": "4. Tesouraria &middot; Reconcilia&ccedil;&atilde;o Tesouraria",
        "img": ("CA-011-012-recon-tesouraria.png", "Reconcilia&ccedil;&atilde;o executada: Conta PI lida da cabine, resultado “Reconciliado” e r&oacute;tulo “Captura nº”."),
        "items": [
            ("CA-011 &nbsp;Leitura da Conta PI e reconcilia&ccedil;&atilde;o", "Corrigido e validado",
             "A tela passou a ler o saldo da Conta PI da cabine PIX (origem camt.053) e a executar a reconcilia&ccedil;&atilde;o entre o saldo real e o raz&atilde;o de clientes do Core, apresentando o resultado “Sem diferen&ccedil;as de transa&ccedil;&atilde;o entre cabine e Core na janela (Reconciliado)”."),
            ("CA-012 &nbsp;R&oacute;tulo do n&uacute;mero de captura", "Corrigido e validado",
             "O r&oacute;tulo t&eacute;cnico foi substitu&iacute;do por “Captura nº”, com explica&ccedil;&atilde;o de que se trata do n&uacute;mero da leitura de dados utilizada na verifica&ccedil;&atilde;o. O mesmo termo foi padronizado nas demais telas que usam captura."),
        ],
    },
    {
        "heading": "5. Tesouraria &middot; Disponibilidades",
        "img": ("CA-013-disponibilidades.png", "Tela Disponibilidades com orienta&ccedil;&atilde;o de estado quando n&atilde;o h&aacute; disponibilidade cadastrada."),
        "items": [
            ("CA-013 &nbsp;Cabine PIX nas Disponibilidades", "Corrigido, item complementar em avaliacao",
             "A tela recebeu a orienta&ccedil;&atilde;o de estado adequada. O saldo da cabine PIX j&aacute; pode ser conferido de forma dedicada nas telas Liquida&ccedil;&atilde;o e Reconcilia&ccedil;&atilde;o Tesouraria (itens CA-001 e CA-011). A exibi&ccedil;&atilde;o de um cart&atilde;o pr&oacute;prio da cabine dentro de Disponibilidades est&aacute; em avalia&ccedil;&atilde;o, para n&atilde;o duplicar a mesma informa&ccedil;&atilde;o em telas distintas."),
        ],
    },
    {
        "heading": "6. Tesouraria &middot; Cr&eacute;ditos SPB Recebidos",
        "img": ("CA-014-creditos-spb.png", "Tela abre listando todos os cr&eacute;ditos recebidos, sem exigir mudan&ccedil;a de filtro."),
        "items": [
            ("CA-014 &nbsp;Filtro padr&atilde;o de status", "Corrigido e validado",
             "A tela passou a abrir com o filtro em “Todos”, exibindo os cr&eacute;ditos recebidos do per&iacute;odo. O usu&aacute;rio refina para “Pendentes” quando quiser tratar exce&ccedil;&otilde;es. A tela n&atilde;o abre mais vazia."),
        ],
    },
    {
        "heading": "7. Relat&oacute;rios &middot; Movimenta&ccedil;&atilde;o CC (extrato do cliente)",
        "img": ("CA-015-018-movimentacao-cc.png", "Extrato com categoria em portugu&ecirc;s, d&eacute;bito em vermelho e cr&eacute;dito em verde, cinco cart&otilde;es de resumo em uma linha e exporta&ccedil;&atilde;o PDF ativa."),
        "items": [
            ("CA-015 &nbsp;Coluna “Categoria” traduzida", "Corrigido e validado",
             "A coluna Categoria passou a exibir os valores em portugu&ecirc;s: “Dep&oacute;sito”, “Transfer&ecirc;ncia” e demais categorias, mantendo o valor t&eacute;cnico interno."),
            ("CA-016 &nbsp;Cores em D&eacute;bito, Cr&eacute;dito e Saldo", "Corrigido e validado",
             "As colunas passaram a seguir a conven&ccedil;&atilde;o cont&aacute;bil: d&eacute;bito em vermelho e cr&eacute;dito em verde, apoiando a leitura r&aacute;pida do extrato, no mesmo padr&atilde;o dos cart&otilde;es de resumo."),
            ("CA-017 &nbsp;Alinhamento dos cart&otilde;es de resumo", "Corrigido e validado",
             "Os cinco cart&otilde;es de resumo (saldo de abertura, total d&eacute;bitos, total cr&eacute;ditos, saldo de fechamento e movimentos) passaram a caber em uma &uacute;nica linha, sem quebra."),
            ("CA-018 &nbsp;Exporta&ccedil;&atilde;o em PDF", "Corrigido e validado",
             "O bot&atilde;o PDF passou a gerar e baixar o extrato. Na valida&ccedil;&atilde;o foi gerado o arquivo do extrato em PDF (comprovante anexo a esta comprova&ccedil;&atilde;o)."),
        ],
    },
    {
        "heading": "8. Relat&oacute;rios &middot; Saldo Di&aacute;rio de Conta Corrente",
        "img": ("CA-019-021-saldo-diario-cc.png", "Card “Contas com saldo” com o total correto e coluna “C&oacute;digo de Conta” preenchida."),
        "items": [
            ("CA-019 &nbsp;Card “Contas com saldo”", "Corrigido e validado",
             "O card passou a exibir a quantidade correta de contas com saldo, no lugar do texto “undefined”."),
            ("CA-020 &nbsp;Coluna “C&oacute;digo de Conta”", "Corrigido e validado",
             "A coluna passou a trazer o c&oacute;digo de cada conta, permitindo distinguir contas do mesmo titular."),
            ("CA-021 &nbsp;Exporta&ccedil;&atilde;o em PDF", "Corrigido e validado",
             "O bot&atilde;o PDF passou a gerar e baixar o relat&oacute;rio, mesmo componente compartilhado corrigido no CA-018 (comprovante anexo)."),
        ],
    },
    {
        "heading": "9. Relat&oacute;rios &middot; Cheque Especial Consolidado",
        "img": ("CA-022-cheque-especial-consolidado.png", "Cinco cart&otilde;es de resumo em uma linha, incluindo IOF do per&iacute;odo."),
        "items": [
            ("CA-022 &nbsp;Alinhamento dos cart&otilde;es de resumo", "Corrigido e validado",
             "Os cinco cart&otilde;es (contratos, limite aprovado, utiliza&ccedil;&atilde;o atual, juros e IOF do per&iacute;odo) passaram a caber em uma &uacute;nica linha, resolvido no mesmo componente compartilhado do CA-017."),
        ],
    },
    {
        "heading": "10. Cadastro &middot; Cliente &middot; Contas &middot; Extrato",
        "img": ("CA-023-extrato-por-conta-carregado.png", "Extrato aberto j&aacute; carregado na conta selecionada, sem necessidade de nova busca."),
        "items": [
            ("CA-023 &nbsp;Extrato a partir da conta do cliente", "Corrigido e validado",
             "Ao acionar “Extrato” na conta do cliente, a tela passou a abrir j&aacute; carregada para aquela conta (identificador passado na navega&ccedil;&atilde;o), sem exigir que o operador digite a conta novamente."),
        ],
    },
    {
        "heading": "11. Cadastro &middot; Gest&atilde;o de Clientes",
        "img": ("CA-024-clientes-paginacao-p3.png", "Pagina&ccedil;&atilde;o funcionando: a p&aacute;gina selecionada permanece ativa."),
        "items": [
            ("CA-024 &nbsp;Pagina&ccedil;&atilde;o da listagem", "Corrigido e validado",
             "A pagina&ccedil;&atilde;o passou a preservar a p&aacute;gina selecionada. Na valida&ccedil;&atilde;o, ao navegar para a p&aacute;gina 3 a sele&ccedil;&atilde;o permaneceu na p&aacute;gina 3, sem retornar &agrave; primeira."),
        ],
    },
    {
        "heading": "12. Tesouraria &middot; Caixa Institucional",
        "img": ("CA-025-menu-tesouraria-sem-caixa-institucional.png", "Menu Tesouraria sem o item “Caixa Institucional”."),
        "items": [
            ("CA-025 &nbsp;Item de menu n&atilde;o utilizado", "Corrigido e validado",
             "O item “Caixa Institucional” foi removido do menu, evitando que o operador acesse uma tela sem funcionalidade. A rota foi preservada para reativa&ccedil;&atilde;o futura por configura&ccedil;&atilde;o."),
        ],
    },
    {
        "heading": "13. Dashboard &middot; Tesouraria &amp; Liquidez",
        "img": ("CA-026-dashboard-tesouraria-liquidez.png", "Card Tesouraria &amp; Liquidez com Disponibilidades positivas e &iacute;ndice de liquidez coerente."),
        "items": [
            ("CA-026 &nbsp;Card “Tesouraria &amp; Liquidez”", "Corrigido e validado",
             "O card passou a apresentar valores coerentes: as Disponibilidades voltaram a exibir valor positivo e plaus&iacute;vel e o &iacute;ndice de liquidez imediata foi recalculado em cascata. O valor negativo de grande magnitude n&atilde;o ocorre mais, e o layout do card foi ajustado."),
        ],
    },
    {
        "heading": "14. STA Admin (Integrador STA)",
        "items": [
            ("STA-001 &nbsp;Gest&atilde;o de usu&aacute;rios e perfis", "Em desenvolvimento",
             "A gest&atilde;o de usu&aacute;rios (cadastro, perfis e permiss&otilde;es) do STA Admin est&aacute; em desenvolvimento. A base de contas e perfis j&aacute; existe no servi&ccedil;o; a interface de administra&ccedil;&atilde;o ser&aacute; disponibilizada em seguida."),
            ("STA-002 &nbsp;Edi&ccedil;&atilde;o do pr&oacute;prio perfil", "Em desenvolvimento",
             "A edi&ccedil;&atilde;o do pr&oacute;prio perfil (nome e troca de senha) faz parte da mesma frente do item STA-001 e ser&aacute; entregue em conjunto."),
        ],
    },
]

INTRO = [
    "Este documento comprova, item a item, o tratamento dado ao Relat&oacute;rio de Bugs do ecossistema Monetarie recebido em 17 de julho de 2026, com 28 registros (26 no CoreAdmin e 2 no STA Admin).",
    "As evid&ecirc;ncias s&atilde;o capturas vivas do ambiente, obtidas em 20 de julho de 2026 sobre a mesma vers&atilde;o publicada em produ&ccedil;&atilde;o. Cada item traz o veredito atual e a imagem da tela correspondente.",
    "Resumo do resultado: 25 dos 26 itens do CoreAdmin est&atilde;o corrigidos e validados; 1 item (CA-013) est&aacute; atendido no essencial, com um complemento visual em avalia&ccedil;&atilde;o; e os 2 itens do STA Admin (STA-001 e STA-002) seguem em desenvolvimento, com entrega prevista em conjunto.",
    "Observa&ccedil;&atilde;o: para que a compara&ccedil;&atilde;o seja fiel, recomendamos revalidar em uma sess&atilde;o nova do navegador (ou com atualiza&ccedil;&atilde;o for&ccedil;ada), pois o carregamento de vers&otilde;es anteriores em cache pode ainda apresentar o comportamento antigo.",
]

CLOSING = [
    "Permanecemos &agrave; disposi&ccedil;&atilde;o para acompanhar a revalida&ccedil;&atilde;o de cada tela em conjunto com a equipe da Monetarie e para conduzir a entrega dos itens do STA Admin ainda em desenvolvimento.",
]


def build(outdir):
    ss = ss_styles()
    out = os.path.join(outdir, "Monetarie-Evidencias-Ajustes-Relatorio-Bugs-2026-07-20.pdf")
    doc = SimpleDocTemplate(
        out, pagesize=A4, leftMargin=20 * mm, rightMargin=20 * mm,
        topMargin=16 * mm, bottomMargin=16 * mm,
        title="Monetarie - Evidencias dos Ajustes do Relatorio de Bugs",
        author="Equipe tecnica Vulci",
    )
    st = []
    st.append(Paragraph("Evid&ecirc;ncias dos Ajustes do Relat&oacute;rio de Bugs", ss["Titulo"]))
    st.append(HRFlowable(width="100%", thickness=2.2, color=GOLD, spaceAfter=8))
    st.append(Paragraph("<b>Para:</b> Monetarie Sociedade de Cr&eacute;dito Direto S.A.", ss["Meta"]))
    st.append(Paragraph("<b>De:</b> Vulci (equipe t&eacute;cnica)", ss["Meta"]))
    st.append(Paragraph("<b>Data:</b> 20 de julho de 2026", ss["Meta"]))
    st.append(Paragraph("<b>Refer&ecirc;ncia:</b> Relat&oacute;rio de Bugs do ecossistema Monetarie, de 17/07/2026 (28 itens)", ss["Meta"]))
    st.append(Spacer(1, 8))
    for p in INTRO:
        st.append(Paragraph(p, ss["Corpo"]))
    for sec in SECOES:
        st.append(Paragraph(sec["heading"], ss["H1x"]))
        for label, status, texto in sec["items"]:
            st.append(KeepTogether([
                Paragraph(f"{label} &nbsp;&middot;&nbsp; {status_html(status)}", ss["ItemTit"]),
                Paragraph(texto, ss["Corpo"]),
            ]))
        for key in ("img", "img2"):
            if sec.get(key):
                name, leg = sec[key]
                p = ev(name)
                if os.path.exists(p):
                    st.append(img_flowable(p))
                    st.append(Paragraph(leg, ss["Legenda"]))
    st.append(Spacer(1, 10))
    for p in CLOSING:
        st.append(Paragraph(p, ss["Corpo"]))
    st.append(Spacer(1, 8))
    st.append(Paragraph("Atenciosamente,", ss["Corpo"]))
    st.append(Paragraph("<b>Equipe t&eacute;cnica Vulci</b>", ss["Corpo"]))
    doc.build(st)
    for t in _tmp:
        try:
            os.remove(t)
        except OSError:
            pass
    return out


if __name__ == "__main__":
    import sys
    outdir = sys.argv[1] if len(sys.argv) > 1 else os.path.expanduser("~/Desktop")
    print(build(outdir))
