# -*- coding: utf-8 -*-
"""Importa o sistema "Premios de entrada" e o calendario de presenca do client.

    python tools/importar_tarefas.py            mostra o que faria
    python tools/importar_tarefas.py --aplicar  grava em server/Data/

Sao tres arquivos do client, os tres com pular_zero=True:

    eventDiary.lod             30 tarefas de tutorial, 1236 bytes por registro
    eventDiary_reward.lod     134 recompensas, 20 bytes por registro
    eventDiary_attendance.lod  14 dias do calendario de presenca

O tipo da recompensa foi decifrado por confirmacao cruzada em 24/08. O arquivo diz que a
tarefa 1030 paga tipo 0 = 200, tipo 1 = 200 e tipo 2 = item 69012; a captura do oficial, no
mesmo milissegundo do resgate, mostrou EXP +200, Carat +200 e um "Saco pequeno" (69012)
entrando no inventario. Tres de tres:

    tipo 0 = EXP        tipo 1 = Carat        tipo 2 = item

A tarefa 1030 e "Caixa de correio", e casa com o `04 06` que o pacote 0a 0d carrega --
0x0406 = 1030. Foi assim que a familia 0a foi identificada como o sistema de tarefas.
"""
import os
import struct
import sys

sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "server"))
import data_files as D                                               # noqa: E402

sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "server"))
import lod_crypto                                                    # noqa: E402

BASE = r"C:\Games\Karos\ResUnpak\Interface\IE_Lod"
DESTINO = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
                       "server", "Data")
NL = chr(10)
BARRA = chr(92)

PASSO_TAREFA = 1236
OFF_NOME = 33          # nome curto, dentro do registro
OFF_TEXTO = 1108       # o texto com "1 vez" que aparece na lista da janela
TIPO = {0: "exp", 1: "carat", 2: "item"}


def escapar(s):
    if s is None:
        return None
    s = str(s).replace(BARRA, BARRA + BARRA)
    s = s.replace(chr(9), BARRA + "t").replace(chr(13), "")
    return s.replace(chr(10), BARRA + "n")


def ler(nome):
    return lod_crypto.decrypt_lod_stream(open(os.path.join(BASE, nome + ".lod_pt"), "rb").read())


def texto_em(d, off, limite=200):
    fim = d.find(b"\x00", off)
    if fim < 0 or fim - off > limite:
        fim = off + limite
    return d[off:fim].decode("latin-1", "replace")


def tarefas():
    d = ler("eventDiary")
    n = struct.unpack_from("<I", d, 0)[0]
    for k in range(n):
        o = 4 + k * PASSO_TAREFA
        if o + PASSO_TAREFA > len(d):
            break
        tid, ordem, _, grupo = struct.unpack_from("<4I", d, o)
        yield {"tarefa_id": tid, "ordem": ordem, "grupo": grupo,
               "nome": texto_em(d, o + OFF_NOME, 60),
               "texto": texto_em(d, o + OFF_TEXTO, 80),
               "instrucoes": texto_em(d, o + 81, 400)}


def recompensas():
    d = ler("eventDiary_reward")
    n = struct.unpack_from("<I", d, 0)[0]
    for k in range(n):
        tid, idx, tipo, valor, qtd = struct.unpack_from("<5I", d, 4 + k * 20)
        yield {"tarefa_id": tid, "indice": idx, "tipo": tipo,
               "tipo_nome": TIPO.get(tipo, str(tipo)), "valor": valor, "quantidade": qtd}


def presenca():
    d = ler("eventDiary_attendance")
    n = struct.unpack_from("<I", d, 0)[0]
    # Registro de tamanho variavel por causa do texto: acha cada um pelo id, que fica no
    # quinto inteiro e cresce a partir de 10001.
    saida, achados = [], []
    for i in range(4, len(d) - 4, 4):
        v = struct.unpack_from("<I", d, i)[0]
        if 10001 <= v <= 10001 + n:
            achados.append((i, v))
    vistos = set()
    for off, v in achados:
        if v in vistos:
            continue
        vistos.add(v)
        saida.append({"dia_id": v, "texto": texto_em(d, off + 8, 200)})
    return saida


def gravar(arquivo, chave, linhas, cabecalho):
    # NAO montar o caminho com DESTINO + nome: depois da reorganizacao de 25/08 isso
    # gravaria Task.ini na RAIZ da Data enquanto o servidor le o de Data/Tasks/ --
    # duas copias, e a que o jogo usa e a que nao foi atualizada.
    cam = D.caminho(arquivo, "Tasks")
    cols = list(linhas[0]) if linhas else []
    with open(cam, "w", encoding="utf-8", newline=NL) as fp:
        fp.write("; " + cabecalho + NL)
        fp.write("; colunas: " + ", ".join(cols) + NL + NL)
        for n, r in enumerate(linhas):
            fp.write("[%s]" % (r[chave] if chave else n) + NL)
            for c in cols:
                v = escapar(r[c])
                if v not in (None, ""):
                    fp.write("%s = %s" % (c, v) + NL)
            fp.write(NL)
    return os.path.getsize(cam)


def main() -> int:
    aplicar = "--aplicar" in sys.argv
    t = list(tarefas())
    r = list(recompensas())
    p = presenca()

    print("Task        : %3d tarefas   (ids %d a %d)"
          % (len(t), t[0]["tarefa_id"], t[-1]["tarefa_id"]))
    print("TaskReward  : %3d recompensas" % len(r))
    import collections
    c = collections.Counter(x["tipo_nome"] for x in r)
    print("              por tipo: %s" % dict(c))
    print("Attendance  : %3d dias de presenca" % len(p))
    print()
    print("primeiras tarefas:")
    for x in t[:4]:
        print("   %d  %-32s %s" % (x["tarefa_id"], x["nome"][:31], x["texto"][:40]))
    print()
    print("recompensas da 1030 (Caixa de correio):")
    for x in r:
        if x["tarefa_id"] == 1030:
            print("   tipo=%-6s valor=%-10d qtd=%d" % (x["tipo_nome"], x["valor"], x["quantidade"]))

    if not aplicar:
        print()
        print("nada gravado. rode com --aplicar")
        return 0

    a = gravar("Task", "tarefa_id", t, "Task -- Premios de entrada, do eventDiary.lod")
    b = gravar("TaskReward", None, r, "TaskReward -- recompensas. tipo 0=exp 1=carat 2=item")
    c2 = gravar("Attendance", "dia_id", p, "Attendance -- calendario de presenca")
    print()
    print("gravados: Task.ini %s B, TaskReward.ini %s B, Attendance.ini %s B"
          % ("{:,}".format(a), "{:,}".format(b), "{:,}".format(c2)))
    return 0


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