# ============================================================
# 12 — Tracer-GAP: reconciling a financial gap with proof
#
# Colab:  !pip install winnex-madhava winnex-tracer
# ============================================================

# instalação automática — Colab, Jupyter e script local.
# No Colab, "!pip" dentro de comentário não executa: a instalação
# precisa acontecer de dentro da célula, antes dos imports.
import importlib
import subprocess
import sys

for _pkg in ["winnex-madhava", "winnex-tracer"]:
    _mod = _pkg.replace("-", "_")
    try:
        __import__(_mod)
        continue
    except ImportError:
        pass
    _r = subprocess.run(
        [sys.executable, "-m", "pip", "install", "-q", "--upgrade", _pkg],
        capture_output=True, text=True
    )
    # O interpretador do Colab já está em execução quando o pip termina.
    # Sem invalidar o cache, o import abaixo pode não enxergar o pacote.
    importlib.invalidate_caches()
    try:
        __import__(_mod)
    except ImportError:
        sys.stderr.write(_r.stdout or "")
        sys.stderr.write(_r.stderr or "")
        raise SystemExit(
            "\n\nNão foi possível importar " + _pkg + " após instalar.\n"
            "No Colab: menu 'Ambiente de execução' -> 'Reiniciar sessão',\n"
            "e execute esta célula novamente.\n"
        )

import random
import numpy as np
import winnex_madhava as mad
from winnex_tracer.core import InstrumentedEngine

DIM = 128
random.seed(12)

def embed(t):
    v = np.zeros(DIM, dtype=np.float32)
    for tok in t.lower().split():
        for i, ch in enumerate(tok):
            v[(ord(ch) * 31 + i * 7) % DIM] += 1.0
    n = np.linalg.norm(v)
    return v / n if n else v

# 1. lançamentos contábeis de um período com divergência
tipos = [
    "lançamento de provisão para devedores duvidosos sem baixa correspondente",
    "estorno de receita registrado em competência distinta do pagamento",
    "transferência entre contas sem documento de suporte anexado",
    "apropriação de despesa antecipada em período incorreto",
    "ajuste de câmbio não refletido no resultado do exercício",
    "baixa de ativo imobilizado sem laudo de desmobilização",
    "reclassificação de despesa operacional para não operacional",
    "provisão trabalhista sem correspondência na folha",
]
lancamentos = [f"LAN-{i+1:05d} {random.choice(tipos)}" for i in range(800)]
corpus = np.stack([embed(l) for l in lancamentos]).astype(np.float32)

base = mad.build_engine(corpus, dim=DIM, k=5, k1_fraction=1.0,
                        postfilter=True, audit_exhaustive=True)
engine = InstrumentedEngine(base, mode="commitment")

# 2. a pergunta da auditoria interna

consulta = "provisão sem baixa ou documento de suporte"
r = engine.search_with_commitment(embed(consulta), k=5)

print(f"lançamentos no período : {len(lancamentos)}")
print(f"lançamentos suspeitos  : {len(r['indices'])}")
print(f"excluídos com prova    : {r['total_excluded_count']}")
print(f"garantia               : {r['recall_guarantee']}")
print(f"bound violations       : {r['bound_violations']}")

print("\nlançamentos para revisão:")
for idx in r["indices"][:3]:
    print(f"  {lancamentos[idx][:72]}")

assert r["bound_violations"] == 0
print("\nOK — 800 lançamentos varridos, exclusões provadas, nenhum omitido.")
