#!/usr/bin/env python3
"""
p4_pack.py — Финальная сборка HBK-файла
"""

import json
import os
import struct

BLOCK_HDR = 31
NO_NEXT = 0x7FFFFFFF
STREAMS_DIR = "hbk_streams"


def make_block_hdr(doc_size, page_size, next_page=NO_NEXT):
    return f"\r\n{doc_size:08x} {page_size:08x} {next_page:08x} \r\n".encode("ascii")


def repack_hbk(original_file, output_file):
    # Читаем оригинальный заголовок
    with open(original_file, "rb") as f:
        orig = f.read(16)

    magic, page_sz, version, reserved = struct.unpack_from("<IIII", orig, 0)

    # Загружаем манифест (порядок потоков!)
    with open(os.path.join(STREAMS_DIR, "_manifest.json"), "r") as f:
        manifest = json.load(f)

    print(f"Потоков: {len(manifest)}")

    # Загружаем потоки
    streams = []
    for entry in manifest:
        name = entry["name"]
        safe = name.replace("/", "_").replace("\\", "_")

        meta_path = os.path.join(STREAMS_DIR, f"{safe}.meta")
        data_path = os.path.join(STREAMS_DIR, safe)

        meta = open(meta_path, "rb").read()
        content = open(data_path, "rb").read()

        streams.append({"name": name, "meta": meta, "content": content})
        print(f"  {name:20s}  data={len(content):>12,} байт")

    # ─── Сборка ──────────────────────────────────────────────────────
    out = bytearray()

    # 1. Заголовок файла (16 байт)
    out += struct.pack("<IIII", magic, page_sz, version, reserved)

    # 2. TOC — заголовок + данные
    n = len(streams)
    toc_doc_size = n * 12
    toc_page_size = ((toc_doc_size + page_sz - 1) // page_sz) * page_sz

    toc_hdr_pos = len(out)
    # Заголовок TOC (заполним позже)
    out += b"\x00" * BLOCK_HDR
    # Данные TOC (заполним позже)
    toc_data_pos = len(out)
    out += b"\x00" * toc_page_size

    # 3. Потоки
    positions = []
    for stream in streams:
        meta = stream["meta"]
        content = stream["content"]

        # Метаданные
        h_pos = len(out)
        meta_page_sz = ((len(meta) + page_sz - 1) // page_sz) * page_sz
        out += make_block_hdr(len(meta), meta_page_sz)
        out += meta
        # Дополнение до page_size
        pad = meta_page_sz - len(meta)
        if pad > 0:
            out += b"\x00" * pad

        # Данные
        d_pos = len(out)
        data_page_sz = ((len(content) + page_sz - 1) // page_sz) * page_sz
        out += make_block_hdr(len(content), data_page_sz)
        out += content
        pad = data_page_sz - len(content)
        if pad > 0:
            out += b"\x00" * pad

        positions.append((h_pos, d_pos))

    # 4. Заполняем TOC
    toc_bytes = bytearray()
    for h_pos, d_pos in positions:
        toc_bytes += struct.pack("<III", h_pos, d_pos, NO_NEXT)

    # Заголовок TOC
    out[toc_hdr_pos : toc_hdr_pos + BLOCK_HDR] = make_block_hdr(
        toc_doc_size, toc_page_size
    )

    # Данные TOC
    out[toc_data_pos : toc_data_pos + len(toc_bytes)] = toc_bytes

    # ─── Сохраняем ───────────────────────────────────────────────────
    with open(output_file, "wb") as f:
        f.write(out)

    orig_sz = os.path.getsize(original_file)
    new_sz = len(out)
    print(f"\n{'=' * 50}")
    print(f"Оригинал: {orig_sz:>12,} байт")
    print(f"Новый:    {new_sz:>12,} байт")
    print(f"Разница:  {new_sz - orig_sz:>+12,} байт")
    print(f"Сохранён: {output_file}")


if __name__ == "__main__":
    repack_hbk("shcntx_ru.hbk", "shcntx_ru_new.hbk")
