# -*- coding: utf-8 -*-
"""Importa os pacotes de item (familia Mixed) para Data/Items/ItemPackage.ini.

    python tools/importar_pacotes.py            mostra
    python tools/importar_pacotes.py --aplicar  grava

DE ONDE VEM

itemMixedMatchBuyDecision.lod, pular_zero=True. Cabecalho de 4, registos de 128 bytes dos
quais so os primeiros 44 tem dado:

    [ 0: 4]  pacote      id da familia Mixed, 700153..900208 -- NAO e um item
    [ 4: 8]  item_id     o item REAL, do catalogo
    [ 8:12]  grau        0 nos primeiros itens do pacote, 1 a partir de certa altura
    [12:16]  ref         210025, 210026... avanca junto com o item
    [16:20]  efeito      da gama 60xxx
    [40:44]  tipo        49 ou 50

O resto dos 128 bytes e zero, tirando um texto tipo "NHN-700153001" que parece um codigo
interno de encomenda.

E A TABELA-MAE DA FAMILIA MIXED

Sao seis ficheiros que partilham o espaco de ids 700xxx, e nenhum deles diz o que esses ids
sao -- sozinhos nao valem nada. Este liga-os ao catalogo:

    matchBuyDecision   pacote -> item real, grau, efeito, tipo    <- este
    Grade              limites do grau (so aparecem 1 e 40)
    Option             pacote -> efeito
    Period             duracao
    Type               10.164 entradas, por abrir
    ExchangeOption     ja importado em ItemExchangeOption.ini

308 pacotes, 1764 itens reais, e os 1764 estao TODOS no catalogo -- e o que da confianca de
que a leitura esta certa.

O GRAU EXPLICA O itemMixedGrade

O campo grau vale 0 nos tres primeiros itens de cada pacote e 1 a partir do quarto, mudando
exatamente onde o efeito salta de 60188/60189 para 60190/60191. Os valores 1 e 40 que o
itemMixedGrade guarda sao os LIMITES do grau, nao o grau.

OS TIPOS 49 E 50, OUTRA VEZ

Cada item aparece em duas linhas, uma de cada tipo: 1764 do 49 e 1764 do 50, sem excecao.
E o quarto sistema onde este par aparece -- ja estava nas pericias de conjunto, na combinacao
e na troca de opcao. Continua sem se saber o que cada um significa; identificar um resolve
os quatro.

O valor de cada efeito vem do skillData.lod, juntado aqui pela mesma razao da troca de
opcao: sem ele a tabela diria "efeito 60188" e nao "+92".
"""
import collections
import os
import struct
import sys

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

BASE = r"C:\Games\Karos\ResUnpak\Interface\IE_Lod"
TAM = 128
TAB = chr(9)
CR = chr(13) + chr(10)


def ler():
    d = lod_crypto.decrypt_lod_stream(
        open(os.path.join(BASE, "itemMixedMatchBuyDecision.lod_pt"), "rb").read())
    n = struct.unpack_from("<I", d, 0)[0]
    saida = []
    for k in range(n):
        off = 4 + k * TAM
        if off + TAM > len(d):
            break
        v = struct.unpack_from("<11I", d, off)
        saida.append((v[0], v[1], v[2], v[3], v[4], v[10]))
    return saida


def ler_efeitos(ids):
    d = lod_crypto.decrypt_lod_stream(
        open(os.path.join(BASE, "skillData.lod_pt"), "rb").read(), pular_zero=False)
    saida = {}
    for e in ids:
        p = d.find(struct.pack("<I", e))
        if p >= 0:
            saida[e] = struct.unpack_from("<d", d, p + 24)[0]
    return saida


def main() -> int:
    aplicar = "--aplicar" in sys.argv
    D.carregar()
    itens = {r["item_id"]: str(r.get("nome") or "?") for r in D.tabela("Item")}
    regs = ler()
    efeitos = ler_efeitos(sorted({r[4] for r in regs}))

    print("registos: %d | pacotes: %d | itens reais: %d"
          % (len(regs), len({r[0] for r in regs}), len({r[1] for r in regs})))
    print("itens reconhecidos no catalogo: %d de %d"
          % (sum(1 for r in regs if r[1] in itens), len(regs)))
    print("efeitos: %d distintos, %d com valor no skillData"
          % (len({r[4] for r in regs}), len(efeitos)))
    print("tipos: %s" % sorted(collections.Counter(r[5] for r in regs).items()))
    print()
    print("%-9s %-11s %-6s %-9s %-6s %-8s %s"
          % ("pacote", "item_real", "grau", "efeito", "tipo", "valor", "nome"))
    for r in regs[:10]:
        v = efeitos.get(r[4])
        print("%-9d %-11d %-6d %-9d %-6d %-8s %s"
              % (r[0], r[1], r[2], r[4], r[5],
                 ("%g" % v) if v is not None else "?", itens.get(r[1], "?")[:32]))

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

    destino = os.path.join(RAIZ, "server", "Data", "Items", "ItemPackage.ini")
    cols = ["pacote", "item_id", "grau", "ref", "efeito", "tipo", "valor", "nome"]
    with open(destino, "w", encoding="utf-8", newline="") as fp:
        w = fp.write
        for l in [
            "; ItemPackage -- pacotes da familia Mixed ligados ao item real.",
            "; Do itemMixedMatchBuyDecision.lod, com o valor do efeito juntado do skillData.lod.",
            ";",
            "; 308 pacotes, 1764 itens reais, todos reconhecidos no catalogo.",
            ";",
            "; E A TABELA-MAE DA FAMILIA MIXED. Sao seis ficheiros que partilham o espaco de ids",
            "; 700xxx e nenhum diz o que esses ids sao -- sozinhos nao valem nada. Este liga-os",
            "; ao catalogo de itens, e por isso destranca os outros:",
            ";",
            ";     Grade     limites do grau (so aparecem 1 e 40)",
            ";     Option    pacote -> efeito",
            ";     Period    duracao",
            ";     Type      10.164 entradas, por abrir",
            ";",
            "; O GRAU explica o itemMixedGrade: vale 0 nos primeiros itens de cada pacote e 1 a",
            "; partir de certa altura, mudando onde o efeito salta de 60188/60189 para",
            "; 60190/60191. O 1 e o 40 daquela tabela sao os LIMITES do grau, nao o grau.",
            ";",
            "; CADA ITEM APARECE EM DUAS LINHAS, uma de tipo 49 e outra de tipo 50, sem excecao.",
            "; E o quarto sistema onde este par aparece (conjunto, combinacao, troca de opcao e",
            "; agora pacotes). Continua sem se saber o que cada tipo significa -- identificar um",
            "; resolve os quatro, e isso mede-se equipando uma peca e vendo o 08 02.",
            ";",
            "; A coluna ref (210025, 210026...) avanca junto com o item. Nome neutro de",
            "; proposito: parece indice de linha ou id de texto, e nao foi confirmado.",
            "",
        ]:
            w(l + CR)
        w("//" + TAB.join(cols) + CR)
        for pacote, item, grau, ref, efe, tipo in regs:
            v = efeitos.get(efe)
            nome = itens.get(item, "")
            w(TAB.join([
                str(pacote), str(item), str(grau), str(ref), str(efe), str(tipo),
                "" if v is None else ("%g" % v),
                (chr(34) + nome + chr(34)) if " " in nome else nome,
            ]) + CR)

    D.carregar()
    t = D.tabela("ItemPackage")
    print()
    print("gravado: %s (%s bytes)" % (destino, "{:,}".format(os.path.getsize(destino))))
    print("relido: %d linhas, colunas %s" % (len(t), list(t[0].keys())))
    return 0


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