# -*- coding: utf-8 -*-
r"""Empacota o que MUDOU no cliente, para levar o jogo patchado para outra maquina.

    python tools/backup_cliente.py                 empacota
    python tools/backup_cliente.py --dias 60       alarga a janela
    python tools/backup_cliente.py --listar        so mostra, nao escreve

PORQUE E UM ZIP A PARTE. O tools/backup.py leva servidor, banco, docs e a memoria do
Claude -- 8 MB que mudam todos os dias. O cliente sao 400 MB que mudam raramente, e
metidos no mesmo ficheiro subiam 400 MB para a nuvem sempre iguais. E a mesma razao
pela qual as gravacoes do oficial ja estao separadas.

O QUE ENTRA: tudo em C:\Games\Axion com data de alteracao dentro da janela. Na pratica:

    Axn.exe                    com os code caves da segunda senha
    Axn.exe.bak_2asenha        o original, para reverter
    IE_Lod/itemAttr.lod_*      refinos 0..18 nos oito idiomas
    IE_Lod/ItemEnchant.lod_*   a tabela de refino
    CheckFileListW.ten         os MD5 recalculados
    Character/Wear/*._OB       as 257 armas com brilho de refino
    *.bak13, *.orig_backup     os originais de cada um

QUASE TUDO ISTO SE REGENERA das ferramentas em tools/ -- mesclar_itemattr.py,
brilho_refino_armas.py, patch_segunda_senha.py -- desde que se tenha um cliente limpo.
O ZIP existe para nao ser preciso: na maquina nova descompacta-se por cima e esta feito.

O QUE NAO ENTRA: o resto do cliente, que sao gigabytes e nao mudaram. Na maquina nova
precisa de haver ja um C:\Games\Axion instalado.
"""
import argparse
import os
import time
import zipfile

RAIZ = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
CLIENTE = r"C:\Games\Axion"
DESTINO = os.path.join(RAIZ, "backups")
DIAS = 30

# Ruido que o proprio jogo escreve a cada arranque -- nao e trabalho nosso.
IGNORAR = (".log", ".tmp", ".dmp", ".etl")
IGNORAR_PASTAS = ("logs", "temp", "cache")


def carimbo():
    return time.strftime("%Y%m%d_%H%M")


def juntar(dias):
    corte = time.time() - dias * 24 * 3600
    achados = []
    for dp, dirs, fs in os.walk(CLIENTE):
        dirs[:] = [x for x in dirs if x.lower() not in IGNORAR_PASTAS]
        for f in fs:
            if os.path.splitext(f)[1].lower() in IGNORAR:
                continue
            p = os.path.join(dp, f)
            try:
                st = os.stat(p)
            except OSError:
                continue
            if st.st_mtime >= corte:
                achados.append((p, os.path.relpath(p, CLIENTE), st.st_size))
    return sorted(achados, key=lambda x: -x[2])


def main() -> int:
    ap = argparse.ArgumentParser(description="Empacota o cliente patchado.")
    ap.add_argument("--dias", type=int, default=DIAS)
    ap.add_argument("--listar", action="store_true")
    args = ap.parse_args()

    if not os.path.isdir(CLIENTE):
        print("nao existe %s" % CLIENTE)
        return 1
    achados = juntar(args.dias)
    total = sum(x[2] for x in achados)
    print("%d ficheiros, %.1f MB (alterados nos ultimos %d dias)"
          % (len(achados), total / 1e6, args.dias))
    print("\nos dez maiores:")
    for _p, rel, tam in achados[:10]:
        print("   %8.1f KB  %s" % (tam / 1e3, rel))

    if args.listar:
        return 0

    os.makedirs(DESTINO, exist_ok=True)
    nome = os.path.join(DESTINO, "axion_cliente_%s.zip" % carimbo())
    with zipfile.ZipFile(nome, "w", zipfile.ZIP_DEFLATED, compresslevel=6) as z:
        for p, rel, _tam in achados:
            try:
                z.write(p, os.path.join("Axion", rel))
            except OSError as e:
                print("   saltado %s: %s" % (rel, str(e)[:60]))
    print("\n%s" % nome)
    print("  %.1f MB comprimido" % (os.path.getsize(nome) / 1e6))
    print("\nna maquina nova: descompactar por cima de C:\\Games\\Axion")
    return 0


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