#!/usr/bin/env python3
"""把 strata-ple 文件的数据段从旧 header 尾巴挪到引擎期望的位置（就地前移，不需额外空间）。

What: 引擎按 strata-ple 解析出 data_start=160，但我们的数据还在 2912（原 50 键 header 留下的位置），
      差 2752 字节 → 报 "PLE table size mismatch". 本脚本把 [2912, EOF) 前移到 160，然后截断。
Why:  strata-ple 的 header 很短（arch 键 + 1 个张量描述 = 141 字节，对齐后 160），
      数据必须紧接其后；而我们的文件是"50 键 header 的壳 + 原位数据"，多出 2752 字节的填充。
How:  顺序前移（dst < src，每块读进内存再写回，安全），块 64 MiB；完成后 truncate。
用法: python3 ple_move_data.py <file> <old_data_start> <new_data_start>
      python3 ple_move_data.py PLE_flash_Q8_fixed.gguf 2912 160
      # 旧起点用 --dry-run 或读取 header 得知；strata-ple 的终点固定是 160
"""
import os, sys

CHUNK = 64 << 20


def main():
    path, old, new = sys.argv[1], int(sys.argv[2]), int(sys.argv[3])
    total = os.path.getsize(path)
    assert new < old, "只做前移"
    move = old - new
    count = total - old
    print(f"{path}\n  文件 {total} 字节；数据 {old} → {new}（前移 {move}），拷贝 {count/2**30:.2f} GiB")
    with open(path, "r+b") as f:
        src, dst, left = old, new, count
        done = 0
        while left > 0:
            f.seek(src)
            chunk = f.read(min(CHUNK, left))
            if not chunk:
                sys.exit("读到文件尾时数据不足")
            f.seek(dst)
            f.write(chunk)
            src += len(chunk); dst += len(chunk); left -= len(chunk)
            done += len(chunk)
            if done % (1 << 30) < CHUNK:            # 每 ~1 GiB 报一次
                print(f"   {done/2**30:.1f} / {count/2**30:.2f} GiB", flush=True)
        f.truncate(new + count)
        f.flush(); os.fsync(f.fileno())
    print(f"完成：{os.path.getsize(path)} 字节（期望 {new+count}）")


if __name__ == "__main__":
    main()
