#!/usr/bin/env python3
"""Native completed seven-game Mini import/qualification and single-game playoffs.

The historical qualified pre-eighth fixture already has seven completed games;
its length is set to7 to test the new completion boundary, without injecting a
result, qualification flag or winner. Historical eight-game import also runs.
"""
from pathlib import Path
import argparse,hashlib,json,struct,subprocess,os
ap=argparse.ArgumentParser(description=__doc__);ap.add_argument('rom',type=Path);ap.add_argument('output',type=Path);ap.add_argument('--qualified',type=Path,required=True);ap.add_argument('--baseline',type=Path,required=True);a=ap.parse_args();h=Path(__file__).resolve().parent;o=a.output.resolve();o.mkdir(exist_ok=True,parents=True);sha=lambda p:hashlib.sha256(p.read_bytes()).hexdigest();assert sha(a.baseline)=='8f84f537ab945ea849ffc69eeba6794e9e1651556d3f878648ed846f8ebc4703'
reports=[]
for profile,rom in [('r11',a.baseline),('current',a.rom)]:
 for length in [7,8]:
  p=o/f'{profile}-length{length}';p.mkdir(exist_ok=True);raw=bytearray(a.qualified.read_bytes());b=bytearray(raw[1::2]);gp=int.from_bytes(b[0x1008:0x100a],'big');assert gp==7,('fixture not naturally at seven games',gp)
  if length==8:
   # Keep this exact historical fixture on its eighth final regular game;
   # normal legacy migration must retain the running length and lock.
   pass
  else:struct.pack_into('>H',b,0x100a,7)
  b[0x1fff]=sum(b[:0x1ffe])%256;b[0x1ffe]=b[0x1fff]^255;raw[1::2]=b;(p/'battery.srm').write_bytes(raw)
  (p/'hook.py').write_text('''from pathlib import Path
import json
observed=[]
def rw(a):return(wram[ram(a)]<<8)|wram[ram(a+1)]
def test_tick(f):
 if f in [1300,2200,3300]:
  b=bytes(sram)[1:16384:2];observed.append(dict(frame=f,slot=rw(0xf06a),playmode=rw(0xd048),header=list(__import__('struct').unpack_from('>6H',b,0x1004)),flag=int.from_bytes(b[0x1210:0x1212],'big'),user=rw(0xd04c),opponent=rw(0xd04e),series=rw(0xceec),menu=bytes(wram[ram(0xe3a2+i)] for i in range(20)).decode('ascii',errors='replace')))
 if f==3300:Path(outdir,'observed.json').write_text(json.dumps(observed,indent=2))
''');(p/'commands.txt').write_text('1300 snap\n1500 press 1 Start 5\n2200 snap\n2500 press 1 Start 5\n3300 snap\n3301 exit\n');env={k:v for k,v in os.environ.items() if not k.startswith('GPGX_')};env.update(GPGX_DEV='513',GPGX_SRM=str(p/'battery.srm'),GPGX_HOOK=str(p/'hook.py'))
  with(p/'log.txt').open('w') as log:subprocess.run(['python3',str(h/'test_core.py'),str(rom.resolve()),str(p/'commands.txt'),str(p)],env=env,stdout=log,stderr=log,check=True,timeout=30)
  rows=json.loads((p/'observed.json').read_text());first=rows[0]
  if profile=='current':
   assert first['slot']==3 and first['header'][2:4]==[7,length],('import changed progress/slot/length',length,first)
   if length==7:assert first['playmode']==2 and first['flag']==1,('Mini7 not single-game playoffs immediately after game7',rows)
   else:assert first['playmode']==0 and first['flag']==0,('unfinished legacy8 must stay on its eighth game',rows)
  reports.append(dict(profile=profile,length=length,observations=rows))
old=next(x for x in reports if x['profile']=='r11' and x['length']==7)['observations'][0];assert old['slot']!=3 or old['playmode']!=2,'historical seven-game boundary defect not reproduced'
(o/'results.json').write_text(json.dumps(dict(rom_sha256=sha(a.rom),baseline_sha256=sha(a.baseline),fixture_sha256=sha(a.qualified),cases=reports,scope=__doc__),indent=2)+'\n');print('PASS completed Mini7→single-game playoffs, native start/legacy8 import, and r11 negative control')
