#!/usr/bin/env python3
"""Actual crowd/reset call: keep the played game's counters across highlights."""
from pathlib import Path
import argparse, hashlib, json, os, struct, subprocess

ap = argparse.ArgumentParser(description=__doc__)
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)
rows = []
for index, (highlight, initialized) in enumerate((x, y) for x in (False, True) for y in (False, True)):
    p = o / str(index)
    p.mkdir(exist_ok=True)
    initial = bytes(range(1, 13)) + (b'GK' if initialized else b'\x12\x34')
    body = [' .text', ' .globl _start', '_start:', ' move.w #0x2700,%sr',
            ' movea.l #0xfffff900,%sp', f' move.b #{16 if highlight else 0},0xffffc2ea',
            ' move.l #0x12345678,0xffffd066']
    for off, value in enumerate(b'CANARIES' + initial + b'BOUNDARY'):
        body.append(f' move.b #{value},0x{0xfffff7f8+off:x}')
    for reg in range(8):
        body.append(f' move.l #0x{0x11223300+reg:x},%d{reg}')
    for reg in range(7):
        body.append(f' movea.l #0x{0xffff1000+256*reg:x},%a{reg}')
    body += [' jsr 0x2e0010', ' move.w %sr,0xffff4800',
             ' movem.l %d0-%d7/%a0-%a6,0xffff4000', ' move.l %sp,0xffff403c',
             ' move.l #0x47525354,0xffff3ff0', 'end: bra.s end']
    (p/'driver.s').write_text('\n'.join(body)+'\n')
    subprocess.run([str(h.parent/'m68kasm.sh'), str(p/'driver.s'), '2d9000', str(p/'code.bin')], check=True, stdout=subprocess.DEVNULL)
    data = bytearray(a.rom.read_bytes())
    code = (p/'code.bin').read_bytes()
    assert data[0x2d9000:0x2d9000+len(code)] == b'\xff'*len(code)
    data[0x2d9000:0x2d9000+len(code)] = code
    struct.pack_into('>I', data, 4, 0x2d9000)
    (p/'driver.bin').write_bytes(data)
    (p/'commands.txt').write_text('100 dump ff3ff0 4 done\n100 dump ff4000 64 regs\n100 dump ff4800 2 sr\n100 dump fff7f8 30 counters\n100 dump ffd066 4 rng\n101 exit\n')
    env = {k:v for k,v in os.environ.items() if not k.startswith('GPGX_')}
    env['GPGX_AUTO_CREDITS'] = '0'
    with (p/'log.txt').open('w') as log:
        subprocess.run(['python3', str(h/'test_core.py'), str(p/'driver.bin'), str(p/'commands.txt'), str(p)], env=env, stdout=log, stderr=log, check=True, timeout=30)
    out = {x.split()[1]:bytes.fromhex(' '.join(x.split()[2:])) for x in (p/'commands.out').read_text().splitlines()}
    assert out['done'] == b'GRST'
    assert out['counters'] == b'CANARIES' + (initial if highlight else bytes(12)+b'GK') + b'BOUNDARY', (highlight, initialized, out['counters'].hex())
    assert out['rng'] == bytes.fromhex('12345678')
    assert struct.unpack('>16I', out['regs']) == tuple([0x11223300+r for r in range(8)] + [0xffff1000+256*r for r in range(7)] + [0xfffff900])
    assert out['sr'] == bytes.fromhex('2700')
    rows.append(dict(highlight=highlight, initialized=initialized, counters_preserved=highlight, fresh_game_cleared=not highlight, register_stack_native_SR_rng_and_neighbor_canaries_preserved=True))
(o/'results.json').write_text(json.dumps(dict(rom_sha256=hashlib.sha256(a.rom.read_bytes()).hexdigest(), cases=rows), indent=2)+'\n')
print('PASS', len(rows), 'actual game-reset/highlight counter lifetime, adjacent canaries and native register/stack/SR/RNG cases')
