# -*- coding: utf-8 -*-
"""Importa a troca de opcao de item para Data/Items/ItemExchangeOption.ini.

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

DE ONDE VEM

itemMixedExchangeOption.lod, pular_zero=True. Cabecalho de 4 e registos de 8:

    [0:4]  item_id     2904 de 2904 sao itens do catalogo
    [4:8]  efeito      da gama 60xxx

Sao 1452 itens, cada um com DOIS efeitos, e 32 efeitos distintos.

O VALOR VEM DE OUTRO FICHEIRO, e e por isso que vale a pena juntar aqui

Os efeitos 60xxx estao todos no skillData.lod (pular_zero=False, registos de 59 bytes):

    [+0]   id do efeito
    [+4]   TIPO -- so aparecem 49 e 50
    [+24]  valor (double)

Testados os 32: todos encontrados. A progressao e limpa -- 92, 100, 108, 116, 124, 140,
156, 173, 191, 210 -- o que confirma que se esta a ler no sitio certo.

Sem esta juncao a tabela seria so "item 400200026 tem os efeitos 60188 e 60189", que nao
diz nada a ninguem. Com ela fica "tem +92 do tipo 49 e +100 do tipo 49".

O QUE 49 E 50 SIGNIFICAM, NAO SE SABE

Sao os dois unicos tipos que aparecem, e os 59 bytes do registo do skillData sao identicos
entre efeitos das duas familias -- so mudam o id, o tipo e o valor. Nao ha no ficheiro nada
que diga se 49 e ataque fisico e 50 e vida, ou o contrario.

Resolve-se pela captura e nao por decifrar mais: equipar uma peca com um efeito conhecido e
ver no 08 02 que estatistica subiu. Dois efeitos de tipos diferentes identificam os dois.

O MESMO ESPACO DE EFEITOS APARECE NOUTROS SISTEMAS

    60188..60203   troca de opcao (este ficheiro)
    60204..60207   pericias de conjunto, 3 pecas
    60241..60244   pericias de conjunto, 4 pecas
    60532..        combinacao de equipamento (ItemCombination.ini)

Descobrir o significado de um tipo resolve os quatro sistemas de uma vez.
"""
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"
TAB = chr(9)
CR = chr(13) + chr(10)


def ler_pares():
    d = lod_crypto.decrypt_lod_stream(
        open(os.path.join(BASE, "itemMixedExchangeOption.lod_pt"), "rb").read())
    n = struct.unpack_from("<I", d, 0)[0]
    return [struct.unpack_from("<2I", d, 4 + k * 8) for k in range(n)]


def ler_efeitos(ids):
    """{efeito: (tipo, valor)} lido do skillData."""
    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:
            continue
        saida[e] = (struct.unpack_from("<I", d, p + 4)[0],
                    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")}
    pares = ler_pares()
    ids = sorted({e for _, e in pares})
    efeitos = ler_efeitos(ids)

    print("pares item-efeito: %d | itens: %d | efeitos distintos: %d"
          % (len(pares), len({i for i, _ in pares}), len(ids)))
    print("efeitos com valor no skillData: %d de %d" % (len(efeitos), len(ids)))
    faltam = [e for e in ids if e not in efeitos]
    if faltam:
        print("SEM valor: %s" % faltam)
    print()
    tipos = collections.Counter(t for t, _ in efeitos.values())
    print("tipos encontrados: %s" % sorted(tipos.items()))
    print()
    print("%-9s %-9s %-9s %s" % ("efeito", "tipo", "valor", "em quantos itens"))
    quantos = collections.Counter(e for _, e in pares)
    for e in ids:
        t, v = efeitos.get(e, ("?", "?"))
        print("%-9d %-9s %-9s %d" % (e, t, ("%.2f" % v) if v != "?" else "?", quantos[e]))

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

    destino = os.path.join(RAIZ, "server", "Data", "Items", "ItemExchangeOption.ini")
    cols = ["item_id", "efeito", "tipo", "valor", "nome"]
    with open(destino, "w", encoding="utf-8", newline="") as fp:
        w = fp.write
        for l in [
            "; ItemExchangeOption -- que opcoes cada item pode receber na troca.",
            "; Do itemMixedExchangeOption.lod, com o valor juntado do skillData.lod.",
            ";",
            "; 1452 itens, DOIS efeitos cada, 32 efeitos distintos. Quase todos trajes.",
            ";",
            "; O valor e o tipo nao estao no mesmo ficheiro que os pares: vieram do",
            "; skillData.lod, onde cada efeito 60xxx tem um registo de 59 bytes com o tipo em",
            "; +4 e o valor (double) em +24. Os 32 foram encontrados.",
            ";",
            "; O TIPO SO TOMA DOIS VALORES, 49 e 50, e NAO SE SABE o que significam. Os 59",
            "; bytes do registo sao identicos entre familias -- so mudam id, tipo e valor.",
            "; Nada no client diz se 49 e ataque fisico e 50 e vida, ou o contrario.",
            ";",
            "; Resolve-se pela captura: equipar uma peca e ver no 08 02 que estatistica subiu.",
            ";",
            "; A MESMA gama de efeitos serve outros sistemas:",
            ";     60188..60203   troca de opcao (este ficheiro)",
            ";     60204..60207   pericias de conjunto, 3 pecas",
            ";     60241..60244   pericias de conjunto, 4 pecas",
            ";     60532..        combinacao de equipamento (ItemCombination.ini)",
            "; Identificar um tipo resolve os quatro de uma vez.",
            "",
        ]:
            w(l + CR)
        w("//" + TAB.join(cols) + CR)
        for item, efe in pares:
            t, v = efeitos.get(efe, (None, None))
            nome = itens.get(item, "")
            w(TAB.join([
                str(item), str(efe),
                "" if t is None else str(t),
                "" if v is None else ("%g" % v),
                (chr(34) + nome + chr(34)) if " " in nome else nome,
            ]) + CR)

    D.carregar()
    t = D.tabela("ItemExchangeOption")
    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())
