# -*- coding: utf-8 -*-
"""Importa o npcInfo.lod do client para dbo.npc.

Registro de 234 bytes, cabecalho de 4 (a contagem: 1227). Campos decodificados em 24/08
comparando registros de mobs conhecidos (Aranha pequena 1001801, Guerreiro Estripador
1000024..) com o que o servidor manda no 04 02:

    [  0:4 ] id do npc            e o mesmo valor que vai em [70:74] do 04 02
    [  4:8 ] grupo de modelo      10018 pra todas as aranhas pequenas, 900/901 animais sagrados
    [  8:12] tipo                 1 npc parado, 2 mob, 4 pet/montaria
    [ 12:16] categoria
    [ 16:20] subcategoria
    [ 60:64] escala/altura        10 na aranha, 19 no estripador
    [ 64:68] 100 em todos         proporcao do modelo, nao HP
    [ 96:104] double              raio (30.0 na aranha)
    [104:112] double              raio maior (200.0 na aranha)
    [132:   ] nome, terminado em zero, latin-1

NAO ha HP, EXP, dano nem spawn aqui: o client nao precisa deles -- recebe HP e posicao
prontos no 04 02. Esses numeros vivem no servidor oficial, que nao temos. Por isso esta
tabela e so o CATALOGO: diz que monstros existem e como desenha-los, nao onde nascem.
"""
import os
import struct
import sys

import pyodbc

sys.path.insert(0, r"D:\RoshEmulator\server")
import lod_crypto

BASE = r"C:\Games\Karos\ResUnpak\Interface\IE_Lod"
CONEXAO = ("DRIVER={ODBC Driver 18 for SQL Server};SERVER=localhost;"
           "DATABASE=Rosh;Trusted_Connection=yes;TrustServerCertificate=yes")
TAM = 234

TABELA = """
IF OBJECT_ID('dbo.npc') IS NOT NULL DROP TABLE dbo.npc;
CREATE TABLE dbo.npc (
    npc_id        BIGINT      NOT NULL PRIMARY KEY,
    nome          NVARCHAR(80) NULL,
    grupo_modelo  INT          NULL,
    tipo          INT          NULL,
    categoria     INT          NULL,
    subcategoria  INT          NULL,
    escala        INT          NULL,
    raio_menor    FLOAT        NULL,
    raio_maior    FLOAT        NULL
);
"""


def registros():
    for suf in ("_pt", "_en", ""):
        cam = os.path.join(BASE, "npcInfo.lod" + suf)
        if os.path.exists(cam):
            break
    else:
        raise SystemExit("nao achei o npcInfo.lod")
    d = lod_crypto.decrypt_lod_stream(open(cam, "rb").read())
    (n,) = struct.unpack_from("<I", d, 0)
    for i in range(n):
        r = d[4 + i * TAM: 4 + (i + 1) * TAM]
        if len(r) < TAM:
            break
        npc_id, modelo, tipo, categoria, sub = struct.unpack_from("<5I", r, 0)
        escala = struct.unpack_from("<I", r, 60)[0]
        raio1, raio2 = struct.unpack_from("<2d", r, 96)
        bruto = r[132:]
        z = bruto.find(b"\x00")
        nome = bruto[:z if z >= 0 else len(bruto)].decode("latin-1", "replace").strip()
        yield (npc_id, nome, modelo, tipo, categoria, sub, escala, raio1, raio2)


def main() -> int:
    linhas = list(registros())
    # ha ids repetidos no arquivo (variacoes do mesmo npc): a chave primaria exige unicos
    vistos, unicas = set(), []
    for l in linhas:
        if l[0] in vistos:
            continue
        vistos.add(l[0])
        unicas.append(l)
    print(f"npcInfo: {len(linhas)} registros, {len(unicas)} ids unicos")

    con = pyodbc.connect(CONEXAO, autocommit=False)
    cur = con.cursor()
    for parte in TABELA.split(";"):
        if parte.strip():
            cur.execute(parte)
    cur.fast_executemany = True
    cur.executemany(
        "INSERT INTO dbo.npc (npc_id, nome, grupo_modelo, tipo, categoria, "
        "subcategoria, escala, raio_menor, raio_maior) VALUES (?,?,?,?,?,?,?,?,?)",
        unicas)
    con.commit()
    cur.execute("SELECT COUNT(*) FROM dbo.npc")
    print(f"dbo.npc: {cur.fetchone()[0]} linhas")
    cur.execute("SELECT TOP 5 npc_id, nome, tipo FROM dbo.npc WHERE tipo = 2 ORDER BY npc_id")
    for l in cur.fetchall():
        print("   ", l[0], repr(l[1]), "tipo", l[2])
    con.close()
    return 0


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