#!/usr/bin/env python3
"""
Импорт своего пака гербов в бот-кланы.

Использование:
    python import-crests.py C:\\путь\\к\\папке_с_гербами
    python import-crests.py C:\\путь --ally     (только альянсовые, 8x16)

Принимает PNG / BMP / DDS. Всё, что не 16x16 (клан) или 8x16 (альянс),
масштабируется автоматически. Результат: server/db_installer/sql/spp_crest_seed.sql
Дальше: docker compose ... up -d --build  и  reset-bots.ps1

Требует: pip install pillow
"""
import sys, os, glob, struct, re, hashlib, random

try:
    from PIL import Image
except ImportError:
    print("Нужен Pillow: pip install pillow"); sys.exit(1)

HERE = os.path.dirname(os.path.abspath(__file__))
SEED_CLAN = os.path.join(HERE, "server", "db_installer", "sql", "spp_clan_seed.sql")
SEED_OUT = os.path.join(HERE, "server", "db_installer", "sql", "spp_crest_seed.sql")

def dds_header(w, h, linear):
    hdr = bytearray(128)
    hdr[0:4] = b'DDS '
    struct.pack_into('<I', hdr, 4, 124)
    struct.pack_into('<I', hdr, 8, 0x0081007)
    struct.pack_into('<I', hdr, 12, h)
    struct.pack_into('<I', hdr, 16, w)
    struct.pack_into('<I', hdr, 20, linear)
    struct.pack_into('<I', hdr, 76, 32)
    struct.pack_into('<I', hdr, 80, 0x4)
    hdr[84:88] = b'DXT1'
    struct.pack_into('<I', hdr, 108, 0x1000)
    return bytes(hdr)

def to565(c):
    return ((c[0] >> 3) << 11) | ((c[1] >> 2) << 5) | (c[2] >> 3)

def encode_dxt1(img):
    """Простое DXT1-сжатие: в каждом блоке 4x4 берём две крайние по яркости краски."""
    w, h = img.size
    px = img.convert("RGB").load()
    body = b''
    for by in range(h // 4):
        for bx in range(w // 4):
            cells = [px[bx * 4 + c, by * 4 + r] for r in range(4) for c in range(4)]
            lum = [0.299 * c[0] + 0.587 * c[1] + 0.114 * c[2] for c in cells]
            cmax = cells[lum.index(max(lum))]
            cmin = cells[lum.index(min(lum))]
            c0, c1 = to565(cmax), to565(cmin)
            if c0 <= c1:
                c0 = min(0xFFFF, c1 + 1)
            idx = 0
            for i, cell in enumerate(cells):
                l = 0.299 * cell[0] + 0.587 * cell[1] + 0.114 * cell[2]
                lo, hi = min(lum), max(lum)
                t = 0 if hi == lo else (l - lo) / (hi - lo)
                sel = 0 if t > 0.83 else (2 if t > 0.5 else (3 if t > 0.17 else 1))
                idx |= (sel & 3) << (i * 2)
            body += struct.pack('<HH', c0, c1) + struct.pack('<I', idx)
    return dds_header(w, h, len(body)) + body

def load_crest(path, w, h):
    if path.lower().endswith(".dds"):
        data = open(path, "rb").read()
        dw = int.from_bytes(data[16:20], 'little'); dh = int.from_bytes(data[12:16], 'little')
        if (dw, dh) == (w, h) and len(data) <= (256 if w == 16 else 192):
            return data           # уже готовый файл нужного размера
        print(f"  ! {os.path.basename(path)}: {dw}x{dh} -> пересобираю")
        return None
    img = Image.open(path)
    if img.size != (w, h):
        img = img.resize((w, h), Image.LANCZOS)
    return encode_dxt1(img)

def main():
    if len(sys.argv) < 2:
        print(__doc__); sys.exit(1)
    folder = sys.argv[1]
    files = []
    for ext in ("png", "bmp", "dds", "jpg", "gif"):
        files += sorted(glob.glob(os.path.join(folder, "**", "*." + ext), recursive=True))
    if not files:
        print("В папке нет картинок"); sys.exit(1)
    print(f"Найдено файлов: {len(files)}")

    clans = re.findall(r"INSERT IGNORE INTO clan_data \(clan_id, clan_name.*?VALUES \((\d+), '([^']+)'",
                       open(SEED_CLAN, encoding="utf-8").read())
    print(f"Кланов в сиде: {len(clans)}")

    out = ["-- SPP crests: imported from " + folder.replace("\\", "/"),
           "DELETE FROM crests WHERE crest_id BETWEEN 9000 AND 9999;"]
    crest_id = 9000
    rnd = random.Random(1)
    ally_size = 8
    allies = [clans[i:i + ally_size] for i in range(0, len(clans), ally_size)]
    A = ["Free","Iron","Silver","Northern","Old","Wild","Royal","United","Dark","Golden","Storm","Silent"]
    B = ["Union","League","Pact","Alliance","Circle","Banner","Order","Coalition"]
    ok = 0
    for ai, group in enumerate(allies):
        if len(group) < 3:
            continue
        name = A[ai % len(A)] + B[(ai // len(A)) % len(B)]
        ally_src = files[ai % len(files)]
        ally_data = load_crest(ally_src, 8, 16) or encode_dxt1(Image.open(ally_src).resize((8, 16)))
        ally_id = crest_id; crest_id += 1
        out.append(f"INSERT INTO crests (crest_id, data, type) VALUES ({ally_id}, 0x{ally_data.hex()}, 3);")
        leader = int(group[0][0])
        for cid, cname in group:
            src = files[hash(cname) % len(files)]
            data = load_crest(src, 16, 16)
            if data is None:
                data = encode_dxt1(Image.open(src).convert("RGB").resize((16, 16), Image.LANCZOS))
            cc = crest_id; crest_id += 1
            out.append(f"INSERT INTO crests (crest_id, data, type) VALUES ({cc}, 0x{data.hex()}, 1);")
            out.append(f"UPDATE clan_data SET crest_id={cc}, ally_id={leader}, ally_name='{name}', ally_crest_id={ally_id} WHERE clan_id={cid};")
            ok += 1
    open(SEED_OUT, "w", encoding="utf-8").write("\n".join(out) + "\n")
    print(f"Готово: {ok} клановых гербов -> {SEED_OUT}")
    print("Дальше: docker compose -f server\\docker\\docker-compose.yml up --build -d  и  reset-bots.ps1")

if __name__ == "__main__":
    main()
