# -*- coding: utf-8 -*-
r"""Poe as tabelas de skill do Arena no NOSSO client, e refaz a lista de integridade.

    python tools/aplicar_skills_arena.py            mostra o que faria
    python tools/aplicar_skills_arena.py --aplicar  copia e reescreve o CheckFileListW
    python tools/aplicar_skills_arena.py --reverter  poe de volta o que estava

O QUE ISTO FAZ E O QUE NAO FAZ. Copia as tabelas de skill ja preparadas em
`backups/client_arena_pronto/` (sem o XOR do Arena, renomeadas para `_pt`) e recalcula os
MD5 no `CheckFileListW.ten` -- sem isso o jogo acusa integridade, porque a lista tem 761
entradas e todas sao conferidas.

O QUE MUDA PARA O JOGADOR. O client passa a conhecer as ~2200 skills que so existem no
client do Arena (de 29/06/2026, contra o nosso de 2019).

O PRECO, e fica dito: o Arena REBALANCEOU o que ja havia. Das 472 linhas de efeito que os
dois clients tem em comum, 404 (85,6%) tem valor diferente -- a Pocao do vento la da +30% e
nos MEDIMOS +45% no oficial. No servidor a mescla ja resolve isso (os nossos valores mandam
onde existem; ver Data/Skills/SkillBuff.ini), mas o CLIENT nao se mescla: ele leva a tabela
do Arena inteira.

Resultado: nas skills que ja existiam, o client passa a MOSTRAR o numero do Arena enquanto o
servidor APLICA o nosso. Sao 15 skills aprendidas nos cinco personagens, entao o estrago e
pequeno -- mas e exactamente o tipo de divergencia que custou o dia 31/08 a caçar.

REVERTER e um comando. O backup de origem esta em
`backups/antes_skills_arena_20260831_2033/client_IE_Lod/`.
"""
import argparse
import hashlib
import os
import shutil
import sys

RAIZ = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, os.path.join(RAIZ, "tools", "debug"))
import ten_crypto as T                                              # noqa: E402

CLIENT = r"C:\Games\Axion"
IE_LOD = os.path.join(CLIENT, "ResUnpak", "Interface", "IE_Lod")
PRONTOS = os.path.join(RAIZ, "backups", "client_arena_pronto")
BACKUP = os.path.join(RAIZ, "backups", "antes_skills_arena_20260831_2033", "client_IE_Lod")
LISTA = os.path.join(CLIENT, "CheckFileListW.ten")
SEED = 0
"""A semente da cifra do .ten. Zero para este ficheiro -- confirmado por o decifrado sair
legivel e o roundtrip fechar."""


def md5(cam):
    h = hashlib.md5()
    with open(cam, "rb") as f:
        for bloco in iter(lambda: f.read(1 << 20), b""):
            h.update(bloco)
    return h.hexdigest()


def refazer_lista(mostrar_so=False):
    """Recalcula o MD5 de cada entrada da lista que aponte para um ficheiro existente."""
    bruto = open(LISTA, "rb").read()
    texto = T.decrypt_ten(bruto, SEED).decode("latin-1")
    linhas = texto.split("\n")
    saida, mudados, ausentes = [], 0, 0
    for l in linhas:
        corpo = l.rstrip("\r")
        if "\t" not in corpo:
            saida.append(l)
            continue
        caminho, _hash = corpo.split("\t", 1)
        real = os.path.join(CLIENT, caminho.lstrip("/").replace("/", os.sep))
        if not os.path.isfile(real):
            ausentes += 1
            saida.append(l)
            continue
        novo = md5(real)
        if novo != _hash:
            mudados += 1
        saida.append(caminho + "\t" + novo + ("\r" if l.endswith("\r") else ""))
    if not mostrar_so:
        novo_txt = "\n".join(saida).encode("latin-1")
        open(LISTA, "wb").write(T.encrypt_ten(novo_txt, SEED))
    return mudados, ausentes, len(linhas)


def main() -> int:
    ap = argparse.ArgumentParser(description="Skills do Arena no client.")
    ap.add_argument("--aplicar", action="store_true")
    ap.add_argument("--reverter", action="store_true")
    args = ap.parse_args()

    origem = BACKUP if args.reverter else PRONTOS
    if not os.path.isdir(origem):
        print("nao existe: %s" % origem)
        return 1
    ficheiros = [f for f in os.listdir(origem)
                 if f.lower().startswith("skill") or f.startswith("SkillTree_")]
    print("%s: %d ficheiros de %s"
          % ("REVERTER" if args.reverter else "aplicar", len(ficheiros), origem))
    for f in sorted(ficheiros)[:6]:
        print("   %s" % f)
    if len(ficheiros) > 6:
        print("   ... e mais %d" % (len(ficheiros) - 6))

    if not (args.aplicar or args.reverter):
        m, a, n = refazer_lista(mostrar_so=True)
        print()
        print("a lista de integridade tem %d linhas; %d hashes ficariam diferentes"
              % (n, m))
        print()
        print("nada foi feito. corra com --aplicar (ou --reverter)")
        return 0

    for f in ficheiros:
        shutil.copy2(os.path.join(origem, f), os.path.join(IE_LOD, f))
    print("copiados %d ficheiros" % len(ficheiros))
    mudados, ausentes, total = refazer_lista()
    print("CheckFileListW.ten reescrito: %d hashes actualizados, %d ficheiros da lista "
          "nao existem no disco (%d linhas)" % (mudados, ausentes, total))
    return 0


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