# -*- coding: utf-8 -*-
import bisect, collections, math, os, re, struct, sys
CAB = re.compile(r"\[([\d:.]+)\] (SEND|RECV) sock=")
HEX = re.compile(r"(?:[0-9A-Fa-f]{2} )+\s*")
def seg(t):
    h, m, s = t.split(":"); return int(h)*3600+int(m)*60+float(s)

def ler(cam, desde=0.0, cauda=None):
    ini = 0
    if cauda:
        ini = max(0, os.path.getsize(cam) - cauda)
    blocos, atual = [], None
    with open(cam, encoding="latin-1", errors="replace") as f:
        if ini: f.seek(ini); f.readline()
        for l in f:
            m = CAB.match(l)
            if m: atual = [m.group(1), m.group(2), bytearray()]; blocos.append(atual)
            elif atual is not None and HEX.fullmatch(l):
                try: atual[2].extend(bytes.fromhex(l.strip()))
                except ValueError: pass
    ev = []
    for t, d, b in blocos:
        s = seg(t)
        if s < desde: continue
        pos = 0
        while pos + 4 <= len(b):
            (n,) = struct.unpack_from(">I", b, pos)
            if n == 0 or n > 65535 or pos+4+n > len(b): break
            ev.append((s, d, bytes(b[pos+4:pos+4+n]))); pos += 4+n
    ev.sort()
    return ev

def analisar(ev, rot):
    jog = [(t, struct.unpack_from("<3f", c, 12)) for t, d, c in ev
           if d == "SEND" and len(c) >= 28 and c[0:2] == bytes([4,1])]
    jog.sort(); ts = [x[0] for x in jog]
    def onde(t):
        i = bisect.bisect_right(ts, t) - 1
        return jog[i][1] if i >= 0 else None
    mov = collections.defaultdict(list); lut = collections.Counter()
    for t, d, c in ev:
        if d != "RECV" or len(c) < 2: continue
        if c[0:2] == bytes([4,1]) and len(c) == 42:
            mov[struct.unpack_from(">I", c, 8)[0]].append((t, c[7], struct.unpack_from("<3f", c, 12)))
        elif c[0:2] == bytes([5,0]) and len(c) >= 11:
            lut[struct.unpack_from(">I", c, 7)[0]] += 1
    parar, raj, pau, larga = [], [], [], []
    est = collections.Counter(); vel = collections.defaultdict(list)
    for e, seq in mov.items():
        seq.sort()
        for i in range(len(seq)-1):
            est[seq[i][1]] += 1
            dt = seq[i+1][0]-seq[i][0]
            if 0.05 < dt < 3:
                vel[seq[i][1]].append(math.dist(seq[i][2][:2], seq[i+1][2][:2])/dt)
        if e not in lut: continue
        ant = ini = fim1 = None
        for t, s_, p in seq:
            j = onde(t); dist = math.dist(p[:2], j[:2]) if j else None
            if s_ != ant:
                if s_ == 2 and ant in (0,1) and dist and dist < 80: parar.append(dist)
                if ant == 1 and s_ != 1:
                    if ini and t-ini < 20: raj.append(t-ini)
                    if dist and dist > 150: larga.append(dist)
                    fim1 = t; ini = None
                if s_ == 1 and ant != 1:
                    ini = t
                    if fim1 and t-fim1 < 20: pau.append(t-fim1)
                ant = s_
    print("=== %s ===" % rot)
    ROT = {0:"andar",1:"correr",2:"parado"}
    for k in sorted(est):
        v = sorted(vel.get(k, []))
        print("   estado %d (%-6s) %6d pacotes   %s" % (k, ROT.get(k,"?"), est[k],
              ("%.1f u/s" % v[len(v)//2]) if len(v) > 5 else ""))
    print("   mobs que combateram: %d" % len(lut))
    for v, r in ((parar,"para para bater a (u)"),(raj,"rajada (s)"),(pau,"pausa (s)"),(larga,"larga a (u)")):
        v = sorted(x for x in v if x > 0.01)
        print("   %-24s n=%-5d %s" % (r, len(v), ("mediana %.2f" % v[len(v)//2]) if len(v) >= 4 else "poucas"))
    print()

analisar(ler(r"C:\RoshHook\traffic.log", desde=17*3600+17*60+28, cauda=8_000_000), "NOSSO (depois das 17:17)")
analisar(ler(r"C:\Users\Administrator\Desktop\CapturaKaros\karos_20260828_1841.log"), "OFICIAL")
