#!/usr/bin/env python3
"""Presentation-only USD formatter: unsigned32-bit ABI/bounds and immutable economy.
Explicit routine probes are not natural matches. Rendered modal screens and
real buy/sell actions are separately required by the exact-ROM release review.
"""
from pathlib import Path
from concurrent.futures import ThreadPoolExecutor
import argparse,hashlib,json,random,struct,sys
from native_probe import NativeProbe
from allstar import catalogue
from transfer_model import Market
ap=argparse.ArgumentParser();ap.add_argument('rom',type=Path);ap.add_argument('output',type=Path);a=ap.parse_args();h=Path(__file__).resolve().parent;o=a.output.resolve();o.mkdir(parents=True,exist_ok=True);b=a.rom.read_bytes();assert b[0x250004:0x250006]==bytes.fromhex('6000');probe=NativeProbe(a.rom,h);seed=bytes((i*71+i//251+11)&255 for i in range(65536));market=Market(catalogue(b));players=list(market.players.values());prices=sorted({market.price(p['uid'])for p in players});assert max(prices)<=9999
fixed=[0,1,9,10,60,99,100,125000,999,1000,9999,10000,65535,65536,99999,100000,999999,1000000,9999999,10000000,99999999,100000000,999999999,1000000000,2147483647,2147483648,4294967294,4294967295,16042,25258,22078,12277,6036,4900,5625,9216,9801,6241]
rng=random.Random(0x55534431);values=sorted(set(fixed+prices+[rng.randrange(2**32)for _ in range(128)]));cases=[dict(value=v,sr=0x2700|(i%32))for i,v in enumerate(values)]+[dict(value=fixed[i%len(fixed)],sr=0x2000|((i//32)<<8)|(i%32))for i in range(256)]
def dollar(v):return '$'+f'{v*1000:,}'.replace(',','.')
def trial(item,selected=None):
 number,cc=item;selected=selected or probe;body=[];wanted=[]
 for i,c in enumerate(cc):
  regs=[0x12345600+k for k in range(8)]+[0xffff1000+256*k for k in range(7)];regs[0]=c['value'];regs[8]=0xfffff160;text=dollar(c['value']);assert len(text)<=18
  body+=[' move.w #0x2700,%sr',' lea 0xfffff140,%a0',' moveq #31,%d0',f'fill_{i}: move.w #0xa65a,(%a0)+',f' dbra %d0,fill_{i}']
  body += [f' move.l #0x{v:x},%d{k}'for k,v in enumerate(regs[:8])]+[f' movea.l #0x{v:x},%a{k}'for k,v in enumerate(regs[8:])]
  at=0xffff4000+130*i;body += [f' move.w #0x{c["sr"]:x},%sr',' jsr 0x250004',f' movem.l %d0-%d7/%a0-%a6,0x{at:x}',f' move.w %sr,0x{at+60:x}',f' move.l %sp,0x{at+62:x}', ' move.w #0x2700,%sr',' lea 0xfffff140,%a0',f' lea 0x{at+66:x},%a1',' moveq #15,%d0',f'copy_{i}: move.l (%a0)+,(%a1)+',f' dbra %d0,copy_{i}'];regs[1]=len(text);wanted.append((regs,text,c))
 raw=selected.run(o/str(number),'\n'.join(body),130*len(cc),sram_data=seed,frames=120)
 for i,(regs,text,c)in enumerate(wanted):
  actual=struct.unpack_from('>15IHI',raw,130*i);assert actual==(*regs,c['sr'],0xffff9800),('USD full ABI/SR/IRQ/CCR/SP',c,actual,regs)
  mem=bytearray(bytes.fromhex('a65a')*32);packet=struct.pack('>H',len(text)+2)+text.encode()+b'\0';mem[32:32+len(packet)]=packet;assert raw[130*i+66:130*i+130]==mem,('USD native packet, decimal grouping or buffer canary',c,text,raw[130*i+66:130*i+130].hex())
 assert(o/str(number)/'probe.srm').read_bytes()==seed,'presentation changed64KB SRAM'
 return len(cc)
with ThreadPoolExecutor(max_workers=3)as pool:count=sum(pool.map(trial,[(i//12,cases[i:i+12])for i in range(0,len(cases),12)]))
# Active regression: a broken .000 suffix must fail the independent monetary
# oracle rather than being approved because a UI string merely contains '$'.
mutant=bytearray(b);needle=bytes.fromhex('10fc002e10fc003010fc003010fc0030');at=mutant.find(needle,0x250000,0x250c00);assert at>=0;mutant[at+7]=49;path=o/'wrong-dollar-scale.bin';path.write_bytes(mutant)
try:trial(('negative',[dict(value=16042,sr=0x271f)]),NativeProbe(path,h))
except AssertionError as exc:
 negative=str(exc);assert 'packet'in negative,negative
else:raise AssertionError('Incorrect monetary suffix escaped')
result=dict(status='passed',ROM_sha256=hashlib.sha256(b).hexdigest(),contexts=count,scale_dollars_per_unit=1000,price='base native OVR squared, unchanged',initial_budget_internal=16042,initial_budget_display=dollar(16042),star99=dollar(9801),middle79=dollar(6241),star_plus_middle_funded=(9801+6241==16042),all_catalogue_price_values_checked=True,unsigned32_max=dollar(4294967295),full_GPR_SR_IRQ_CCR_SP=True,output21byte_bound=True,all64KB_SRAM_unchanged=True,active_wrong_scale_negative=negative,scope=__doc__);(o/'result.json').write_text(json.dumps(result,indent=2)+'\n');print('PASS',count,'USD native contracts, all price values/U32/ABI/canaries/SRAM, active wrong-scale negative',flush=True)
