"""Copy the original Milky Way generator's actual GDM inputs, without a game process.

The 32-bit mass-density rows and the three 16-bit maps have different RLE
word widths.  Their pointers are the exact fields consumed by 4CA5370,
4CA5940, 4CA5A20 and 4CA5240 in the pinned original image.  Values are retained
as integers; this is not the normalized, one-channel overview export.
"""
from pathlib import Path
import gzip, hashlib, json, struct

directory=Path('artifacts/navigation-0410-qa/resources')
key='d30f11c57448cff8ec3dd0c5c80d9868482ccadb'
f=(directory/(key+'.fres')).read_bytes()
b=(directory/(key+'.bin')).read_bytes()
if hashlib.sha256(f).hexdigest()!='745b9cfbeb501fc83eba4e64822ee7a2953d1cf1c293afc1ed5c32469a3fdf2d':raise ValueError('Original resource header changed')
if len(b)!=82232836 or hashlib.sha256(b).hexdigest()!='49a18ad1f339169391abe2a76475eea6731028b9809d7120fb32d57309196f22':
    raise ValueError('Original frozen resource changed')
np,nr=struct.unpack_from('<I',f,0x34)[0],struct.unpack_from('<I',f,0x20)[0]
if (np,nr)!=(3227,24):raise ValueError('Original frozen schema changed')
cursor=0;grouped=0
while grouped<np:
    kind,count=struct.unpack_from('<HH',b,cursor);cursor+=4;grouped+=count
pools=[struct.unpack_from('<8I',b,cursor+i*32) for i in range(np)];cursor+=np*32
roots=[struct.unpack_from('<4I',b,cursor+i*16) for i in range(nr)];cursor+=nr*16
start=len(b)-sum(p[2] for p in pools)
if start!=13127884 or start-cursor!=814013*16+16:raise ValueError('Relocation boundary changed')
refs={}
for i in range(814013):
    p,o,q,v=struct.unpack_from('<4I',b,cursor+i*16)
    if p>=np or q>=np or o>=pools[p][2] or v>=pools[q][2] or (p,o) in refs:raise ValueError('Invalid original relocation')
    refs[p,o]=q,v
def at(p,o):
    if p>=np or not 0<=o<pools[p][2]:raise ValueError('Original pointer outside pool')
    return start+pools[p][3]+o
root=next(r[2:] for r in roots if r[:2]==(2854198236,193492573))
if root!=(2075,2048):raise ValueError('Original GDM root changed')
rp,ro=root;root_at=at(rp,ro)
coefficients=list(struct.unpack_from('<14I',b,root_at))
if coefficients[11:]!=[100000,81910,100000]:raise ValueError('Original galaxy extent changed')
origin_root=next(r[2:] for r in roots if r[:2]==(1765098201,2090718614))
origin=[value/32 for value in struct.unpack_from('<3i',b,at(*origin_root))]
if origin!=[49985,40985,24105]:raise ValueError('Original Sol origin changed')
payload=bytearray();maps=[]
for field,bits,name in [(0x38,32,'massDensity0'),(0x78,16,'dustSurfaceIntegral'),(0x138,16,'milkyWaySurface'),(0x140,16,'radialHeightIntegral')]:
    p,o=refs[rp,ro+field];a=at(p,o);width,height,source_bytes=struct.unpack_from('<3I',b,a)
    if width!=2048 or height!=2048:raise ValueError('Original map dimensions changed')
    rows=refs[p,o+16];word=bits//8;fmt='<I' if bits==32 else '<H';repeat=1<<(bits-1);length_mask=repeat-1
    expanded=bytearray();raw_bytes=0
    for z in range(height):
        pos=at(*refs[rows[0],rows[1]+z*8]);row_start=pos;x=0
        while x<width:
            header=struct.unpack_from(fmt,b,pos)[0];pos+=word;length=header&length_mask
            if not 0<length<=width-x:raise ValueError(f'Invalid original RLE run at {field:x}/{z}/{x}')
            if header&repeat:
                value=b[pos:pos+word];pos+=word;expanded.extend(value*length)
            else:
                expanded.extend(b[pos:pos+word*length]);pos+=word*length
            x+=length
        raw_bytes+=pos-row_start
    if raw_bytes+height*8!=source_bytes:raise ValueError(f'Original RLE byte count differs: field={field:x}, rows={raw_bytes}, descriptor={source_bytes}')
    offset=len(payload);payload.extend(expanded)
    maps.append(dict(name=name,field=hex(field),root=[p,o],width=width,height=height,bits=bits,
        offset=offset,bytes=len(expanded),rleBytes=source_bytes,sha256=hashlib.sha256(expanded).hexdigest()))
out=Path('XFEEDToolBox.Core/Rendering')
compressed=gzip.compress(payload,compresslevel=9,mtime=0)
(out/'original-galaxy-density.bin.gz').write_bytes(compressed)
metadata=dict(sourceResource=key,sourceFrozenSha256=hashlib.sha256(b).hexdigest(),sourceFresSha256=hashlib.sha256(f).hexdigest(),
    gameImageSha256='6891f70a021fa9f3a0e00458c284f48d1226e68ae7fc02ad48081aed47857e93',root=list(root),sourceOrigin=origin,
    coefficients=coefficients,maps=maps,payloadBytes=len(payload),payloadSha256=hashlib.sha256(payload).hexdigest(),
    gameProcessAccess=False,gameCalls=0,networkRequests=0,normalizationApplied=False)
(out/'original-galaxy-density.json').write_text(json.dumps(metadata,indent=2)+'\n',encoding='utf-8')
print(json.dumps(dict(maps=len(maps),payloadBytes=len(payload),compressedBytes=len(compressed),payloadSha256=metadata['payloadSha256'])))
