# -*- coding: utf-8 -*-
"""Importa classChange.lod para dbo.classe_evolucao: a arvore de promocao de classe.

Registro de 24 bytes, cabecalho de 4 (144 registros):
    [ 0:4 ] classe resultante     110, 111, 112, 120...
    [ 4:8 ] grau                  0, 1, 2
    [ 8:12] vem de                a classe anterior
    [12:16] nivel minimo          10, 25, 40, 45, 60, 75
    [16:20] custo                 10000 .. 500000
    [20:24] requisito             id de quest/item, 0 quando nao ha

Achado em 24/08 quando o jogador entrou com uma Banshee nivel 68 e o HP nao fechou com
a formula: 3757 medidos contra 2589 previstos pela curva da Maga. A promocao muda a
progressao -- as curvas que medimos valem para as 7 classes BASE, e so ate a primeira
promocao (nivel 10).

Isso tambem explica os nomes das 49 tabelas SkillTree_*: 100, 110, 111, 112, 120... sao
exatamente os codigos daqui. Cada evolucao tem arvore de skill propria.
"""
import os
import struct
import sys

import pyodbc

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

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 = 24

TABELA = """
IF OBJECT_ID('dbo.classe_evolucao') IS NOT NULL DROP TABLE dbo.classe_evolucao;
CREATE TABLE dbo.classe_evolucao (
    classe     INT NOT NULL,
    grau       INT NOT NULL,
    vem_de     INT NOT NULL,
    nivel_min  INT NOT NULL,
    custo      BIGINT NULL,
    requisito  BIGINT NULL,
    PRIMARY KEY (classe, grau)
);
"""


def main() -> int:
    for suf in ("_pt", "_en", ""):
        cam = os.path.join(BASE, "classChange.lod" + suf)
        if os.path.exists(cam):
            break
    else:
        raise SystemExit("nao achei o classChange.lod")
    d = lod_crypto.decrypt_lod_stream(open(cam, "rb").read())
    (n,) = struct.unpack_from("<I", d, 0)

    linhas, vistos = [], set()
    for i in range(n):
        r = d[4 + i * TAM: 4 + (i + 1) * TAM]
        if len(r) < TAM:
            break
        classe, grau, vem, nivel, custo, req = struct.unpack_from("<6I", r, 0)
        if not classe or (classe, grau) in vistos:
            continue
        vistos.add((classe, grau))
        linhas.append((classe, grau, vem, nivel, custo, req or None))

    con = pyodbc.connect(CONEXAO, autocommit=False)
    cur = con.cursor()
    for parte in TABELA.split(";"):
        if parte.strip():
            cur.execute(parte)
    cur.executemany("INSERT INTO dbo.classe_evolucao (classe, grau, vem_de, nivel_min, "
                    "custo, requisito) VALUES (?,?,?,?,?,?)", linhas)
    con.commit()

    print("dbo.classe_evolucao: %d linhas\n" % len(linhas))
    cur.execute("SELECT DISTINCT vem_de FROM dbo.classe_evolucao WHERE vem_de IN "
                "(100,200,300,400,500,600,800) ORDER BY vem_de")
    raizes = [l[0] for l in cur.fetchall()]
    nomes = {100: "Guerreiro", 200: "Paladina", 300: "Vagabundo", 400: "Feiticeira",
             500: "Arqueira", 600: "Maga", 800: "Artilheiro"}
    for r in raizes:
        cur.execute("SELECT classe, nivel_min, custo FROM dbo.classe_evolucao "
                    "WHERE vem_de = ? AND grau = 0 ORDER BY classe", r)
        filhos = cur.fetchall()
        print("%-12s (%d) -> %s" % (nomes.get(r, "?"), r,
              ", ".join("%d no nivel %d" % (f[0], f[1]) for f in filhos)))
    print()
    cur.execute("SELECT DISTINCT nivel_min FROM dbo.classe_evolucao ORDER BY nivel_min")
    print("niveis de promocao: " + ", ".join(str(l[0]) for l in cur.fetchall()))
    con.close()
    return 0


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