# -*- coding: utf-8 -*-
r"""Junta VARIAS capturas do mesmo lado e mede o mob sobre o conjunto todo.

    python tools/juntar_mob.py --oficial <log> [<log> ...] --nosso <log> [<log> ...]
    python tools/juntar_mob.py --auto

PORQUE EXISTE. Correr o comparar_mob ficheiro a ficheiro e olhar para as medianas nao chega:
uma captura de 4 minutos da 4 cacadas, e a mediana de 4 amostras nao decide se uma constante
esta certa. Aqui juntam-se as amostras CRUAS antes de tirar a mediana -- que e diferente de
fazer a media das medianas, porque essa deixa uma captura magra pesar tanto como uma gorda.

Foi por medir com poucas amostras que em 28/08 se concluiu que "perseguir nao muda a
velocidade": 21 pacotes de corrida contra 1739 de passeio, e a corrida afogou-se na media.

A ARMADILHA DA FUSAO, e como se evita. O ficheiro de 113 MB cobre das 19:50 as 22:17 e
ENGOLE as janelas de duas capturas mais pequenas. Como os carimbos sao hora-do-dia, a mesma
entidade nas duas dava uma sequencia entrelacada, com intervalos minusculos inventados pela
fusao -- que e precisamente a grandeza que se quer medir. Por isso cada captura leva um
deslocamento de tempo proprio: assim `corridas()` nunca consegue ligar um passo de um
ficheiro ao passo do seguinte.
"""
import copy
import os
import sys

sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "analise"))
import metricas as M                                                # noqa: E402

AFASTA = 1_000_000.0      # segundos entre capturas: muito acima do BURACO de 2 s


def juntar(caminhos, log=print):
    """Carrega e funde as capturas, cada uma no seu proprio pedaco da linha do tempo."""
    total = {"mov": {}, "npc": {}, "golpes": [], "danos": [], "jogador": []}
    usados = []
    for i, cam in enumerate(caminhos):
        if not os.path.isfile(cam):
            log("   (falta %s)" % cam)
            continue
        try:
            ev = M.carregar(cam)
        except Exception as e:                                      # noqa: BLE001
            log("   (%s falhou: %s)" % (os.path.basename(cam), str(e)[:60]))
            continue
        d = i * AFASTA
        n_mov = 0
        for ent, seq in ev["mov"].items():
            # a entidade E do ficheiro: ids repetem-se entre capturas e sao gente diferente
            chave = (i, ent)
            total["mov"][chave] = [(s[0] + d,) + tuple(s[1:]) for s in seq]
            n_mov += len(seq)
        for ent, npc in ev["npc"].items():
            total["npc"][(i, ent)] = npc
        total["golpes"] += [(g[0] + d, (i, g[1]), (i, g[2])) + tuple(g[3:]) for g in ev["golpes"]]
        total["danos"] += [(x[0] + d,) + tuple(x[1:]) for x in ev["danos"]]
        total["jogador"] += [(t + d, x, y) for t, x, y in ev["jogador"]]
        usados.append((os.path.basename(cam), n_mov, len(ev["golpes"])))
    total["jogador"].sort()
    return total, usados


def main() -> int:
    args = sys.argv[1:]
    if not args:
        print(__doc__)
        return 2
    grupos, atual = {}, None
    for a in args:
        if a.startswith("--"):
            atual = a[2:]
            grupos.setdefault(atual, [])
        elif atual:
            grupos[atual].append(a)

    saida = {}
    for lado in ("oficial", "nosso"):
        cams = grupos.get(lado, [])
        if not cams:
            continue
        print("== %s: %d capturas ==" % (lado.upper(), len(cams)))
        ev, usados = juntar(cams)
        for nome, nm, ng in usados:
            print("   %-32s %6d passos, %4d golpes" % (nome, nm, ng))
        saida[lado] = M.medir(ev)
        print()

    if len(saida) == 2:
        _tabela(saida["oficial"], saida["nosso"])
    elif saida:
        for fase, campos in list(saida.values())[0].items():
            print("%s: %s" % (fase, campos))
    return 0


def _tabela(o, n):
    ROTULOS = {
        "corridas": "trechos", "dt": "intervalo entre passos (s)", "passo": "avanco por passo (u)",
        "vel": "VELOCIDADE (u/s)", "decl": "distancia declarada (u)", "vel_decl": "velocidade declarada",
        "giro": "quanto VIRA entre passos (gr)", "giro_p90": "virada dos 10% piores (gr)",
        "recto_pc": "passos em linha recta (%)", "solavanco": "salto de velocidade",
        "arranque": "arranque (1 = sem)", "duracao": "duracao de um trecho (s)",
        "duracao_max": "trecho mais longo (s)", "percorrido": "quanto persegue (u)",
        "regressos": "regressos ao poste", "golpes": "golpes de mob",
        "cadencia": "intervalo entre golpes (s)", "sessao": "duracao de uma luta (s)",
    }
    for fase in ("passeio", "perseguicao", "parado", "combate"):
        if fase not in o or not isinstance(o[fase], dict):
            continue
        print("%s" % fase.upper())
        print("  %-32s %10s %12s %10s" % ("", "OFICIAL", "NOSSO", "erro"))
        print("  " + "-" * 66)
        for k in o[fase]:
            if k not in n.get(fase, {}):
                continue
            a, b = o[fase][k], n[fase][k]
            if not isinstance(a, (int, float)) or not isinstance(b, (int, float)):
                continue
            if a == 0 and b == 0:
                continue
            base = abs(a) if a else abs(b)
            err = abs(a - b) / base * 100 if base else 0.0
            marca = "  <<" if err > 20 else ""
            print("  %-32s %10.3f %12.3f %9.0f%%%s"
                  % (ROTULOS.get(k, k), a, b, err, marca))
        print()


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