# -*- coding: utf-8 -*-
"""Importa as lojas dos NPC do client para Data/Shop/, um ficheiro por loja.

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

DE ONDE VEM

Duas tabelas do client, ambas com pular_zero=True:

  npcShopItem.lod   1022 registos de 12 bytes, cabecalho de 4:
      [0:4]   id da loja
      [4:8]   id do item
      [8:12]  posicao dentro da loja (recomeca em 1 a cada loja)

  npcShop.lod       282 registos de 138 bytes, cabecalho de 4:
      [0:4]   npc_id
      [4:8]   regiao (19002, 19003, 19014... os mesmos ids da tabela de mapas)
      [8:12]  id da loja, ou 0 se o NPC nao vende nada
      resto   texto e numeros que nao decodifiquei

O CAMPO DA LOJA ESTA EM +8, e nao em +16 como cheguei a escrever. O engano veio de um dump
meu que imprimia `d[off-8:off+28]` com off=4: como max(0, -4) da 0, a fatia comecava no
inicio do ficheiro e ficava quatro bytes desalinhada da que eu julgava estar a ver. O sintoma
era 1079574528 em quase todos os NPC -- que e o float 3.0 lido como inteiro, sinal de que se
esta a ler no sitio errado.

O QUE FICA DE FORA

Quatro lojas nao tem NPC nenhum a aponta-las: 206, 509, 10000 e 10001. As duas ultimas tem
286 e 62 itens, de longe as maiores, e sao quase de certeza a loja de dinheiro real -- que
nao se abre falando com ninguem. Ficam gravadas na mesma, com npc vazio.

Do lado inverso, 168 dos 253 NPC do npcShop tem loja 0: existem na tabela mas nao vendem.

PRECOS

Nao estao aqui. O npcShopItem so diz QUE itens a loja tem e por que ordem. O preco esta no
proprio item, nas colunas preco_compra e preco_venda do Item.ini.
"""
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_ITEM, CAB_ITEM = 12, 4
TAM_SHOP, CAB_SHOP = 138, 4
CR = chr(13) + chr(10)


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


def ler_itens():
    """{loja: [(posicao, item_id)]}"""
    d = _abre("npcShopItem")
    n = struct.unpack_from("<I", d, 0)[0]
    saida = collections.defaultdict(list)
    for k in range(n):
        off = CAB_ITEM + k * TAM_ITEM
        if off + TAM_ITEM > len(d):
            break
        loja, item, pos = struct.unpack_from("<3I", d, off)
        saida[loja].append((pos, item))
    for v in saida.values():
        v.sort()
    return saida


def ler_donos():
    """{loja: [(npc_id, regiao)]} -- quem vende cada loja."""
    d = _abre("npcShop")
    n = struct.unpack_from("<I", d, 0)[0]
    saida = collections.defaultdict(list)
    for k in range(n):
        off = CAB_SHOP + k * TAM_SHOP
        if off + 12 > len(d):
            break
        npc, regiao, loja = struct.unpack_from("<3I", d, off)
        if loja:
            saida[loja].append((npc, regiao))
    return saida


def main() -> int:
    aplicar = "--aplicar" in sys.argv
    D.carregar()
    itens_cat = {r["item_id"]: r for r in D.tabela("Item")}
    npcs = {r["npc_id"]: str(r.get("nome") or "?") for r in D.tabela("Npc")}

    lojas = ler_itens()
    donos = ler_donos()
    print("lojas com itens: %d | lojas com dono: %d" % (len(lojas), len(donos)))
    print()
    print("%-8s %-7s %-30s %-9s %s" % ("loja", "itens", "vendida por", "regiao", "exemplo"))
    print("-" * 92)
    for loja in sorted(lojas):
        lista = lojas[loja]
        quem = donos.get(loja, [])
        nomes = ", ".join(npcs.get(npc, str(npc)) for npc, _ in quem[:3]) or "(sem NPC)"
        regiao = quem[0][1] if quem else ""
        ex = ", ".join(str((itens_cat.get(i) or {}).get("nome") or i)[:20] for _, i in lista[:2])
        print("%-8d %-7d %-30s %-9s %s" % (loja, len(lista), nomes[:30], regiao, ex))

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

    destino = os.path.join(RAIZ, "server", "Data", "Shop")
    os.makedirs(destino, exist_ok=True)
    # limpa ficheiros de uma importacao anterior, para uma loja que desapareca nao ficar orfa
    for f in os.listdir(destino):
        if f.startswith("Shop_") and f.endswith(".ini"):
            os.remove(os.path.join(destino, f))

    for loja in sorted(lojas):
        lista = lojas[loja]
        quem = donos.get(loja, [])
        cam = os.path.join(destino, "Shop_%d.ini" % loja)
        # newline="" e nao newline=CR. Com newline=CR o Python traduz o fim de linha
        # sozinho, e como aqui ja se escreve o CR a mao cada linha saia com o fim de
        # linha DUPLICADO -- que num editor de Windows aparece como uma linha em branco
        # entre cada duas. Era o que estava a acontecer em todos os Shop_*.ini.
        with open(cam, "w", encoding="utf-8", newline="") as fp:
            w = fp.write
            w("; Loja %d -- o que este NPC vende." % loja + CR)
            w("; colunas: posicao, item_id, nome, preco_compra, preco_venda" + CR)
            w(";" + CR)
            if quem:
                for npc, regiao in quem:
                    w("; vendida por %s (npc %d), regiao %d" % (npcs.get(npc, "?"), npc, regiao) + CR)
            else:
                w("; SEM NPC. Nenhum npcShop aponta para esta loja -- as 10000 e 10001, que sao" + CR)
                w("; as maiores de todas, sao quase de certeza a loja de dinheiro real." + CR)
            w(";" + CR)
            w("; O preco vem do proprio item (Item.ini), nao da loja: a mesma pocao custa o" + CR)
            w("; mesmo em qualquer sitio. Fica copiado aqui so para se ler de uma vez." + CR)
            w(CR)
            # TABULAR, e nao uma seccao [n] por item. Uma loja de 20 artigos ocupava 148
            # linhas em blocos de seis, e era preciso rolar para comparar dois precos. Em
            # tabela sao 29 linhas e le-se tudo de uma vez -- o mesmo formato das outras
            # tabelas de Data.
            w("//" + "	".join(("posicao", "item_id", "nome",
                                "preco_compra", "preco_venda")) + CR)
            for pos, item in lista:
                r = itens_cat.get(item) or {}
                nome = str(r.get("nome") or "").replace(chr(13), "").replace(chr(10), " ")
                nome = nome.replace(chr(9), " ")     # tabulacao no nome partia a coluna
                w("	".join((str(pos), str(item), nome,
                             str(r.get("preco_compra") if r.get("preco_compra") is not None else ""),
                             str(r.get("preco_venda") if r.get("preco_venda") is not None else "")))
                  + CR)
    total = sum(len(v) for v in lojas.values())
    print()
    print("gravado: %d ficheiros em %s (%d itens no total)" % (len(lojas), destino, total))
    return 0


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