# -*- coding: utf-8 -*-
"""Tira os nomes de personagem que aparecem numa captura.

E a prova decisiva de a captura ser NOSSA ou do OFICIAL: os nomes vivem em bases de dados
diferentes. Assinaturas de opcode enganam -- o oficial tambem manda 08 01, so que nao para a
regeneracao, e foi por confiar nisso que a primeira triagem de 28/08 marcou tudo como nosso.
"""
import collections
import io
import os
import re
import sys

CAB = re.compile(r"^\[(\d\d):(\d\d):(\d\d)\.(\d+)\] (SEND|RECV) sock=(\S+) len=(\d+)")
HEX = re.compile(r"^[0-9A-Fa-f ]+$")
PALAVRA = re.compile(rb"[A-Za-z][A-Za-z0-9_.-]{2,19}")

# lixo que aparece nos buffers de recursos do client, nao sao nomes de gente
RUIDO = re.compile(
    r"^(Res|Unpak|Map|Tree|Shaders|Model|Birch|Forest|Manager|CSpeed|Unable|retrieve|maps|from|"
    r"loaded|cannot|populate|randomly|mu\d+|Effect|Sound|Texture|Anim|Script|Data|Char|Item|"
    r"Skill|Quest|NPC|Mob|Field|Zone|Camera|Light|Water|Sky|Terrain|Font|UI|Icon|Cursor)",
    re.I)


def nomes(caminho, limite_bytes=None):
    cont = collections.Counter()
    atual, buf = None, []

    def fechar():
        if atual is None:
            return
        try:
            b = bytes.fromhex("".join(buf))
        except ValueError:
            return
        for m in PALAVRA.finditer(b):
            s = m.group().decode("latin-1")
            if not RUIDO.match(s):
                cont[s] += 1

    lidos = 0
    with io.open(caminho, encoding="latin-1", errors="ignore") as f:
        for ln in f:
            lidos += len(ln)
            if limite_bytes and lidos > limite_bytes:
                break
            m = CAB.match(ln)
            if m:
                fechar()
                atual, buf = m.group(5), []
            elif atual and HEX.match(ln.strip()):
                buf.append(ln.strip().replace(" ", ""))
    fechar()
    return cont


def main() -> int:
    if len(sys.argv) < 2:
        print(__doc__)
        return 2
    nossos = set()
    try:
        sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "server"))
        import db
        con = db._conectar()
        if con is not None:
            cur = con.cursor()
            cur.execute("SELECT nome FROM dbo.personagem")
            nossos = {r[0] for r in cur.fetchall()}
    except Exception as e:                                            # noqa: BLE001
        print("(sem banco: %s)" % str(e)[:60])
    print("personagens da NOSSA base: %s" % (", ".join(sorted(nossos)) or "(nenhum)"))
    print()

    for cam in sys.argv[1:]:
        mb = os.path.getsize(cam) / 1e6
        lim = 40_000_000 if mb > 60 else None
        c = nomes(cam, lim)
        batem = {n: c[n] for n in nossos if c.get(n)}
        print("%s  (%.1f MB%s)" % (os.path.basename(cam), mb, ", so o inicio" if lim else ""))
        if batem:
            print("   NOSSA -- nomes da nossa base presentes: %s"
                  % ", ".join("%s x%d" % kv for kv in sorted(batem.items())))
        else:
            print("   nenhum nome da nossa base aparece -> provavelmente do OFICIAL")
        print("   palavras mais repetidas: %s"
              % ", ".join("%s(%d)" % kv for kv in c.most_common(12)))
        print()
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
