#!/usr/bin/env python3
"""Paired live attack: native pass to an open slot and off-puck support/marking."""
from pathlib import Path
from concurrent.futures import ThreadPoolExecutor
import argparse,json,os,subprocess,statistics
ap=argparse.ArgumentParser(description=__doc__);ap.add_argument('rom',type=Path);ap.add_argument('output',type=Path);ap.add_argument('--baseline',type=Path,required=True);ap.add_argument('--state',type=Path,required=True);a=ap.parse_args();out=a.output.resolve();out.mkdir(parents=True,exist_ok=True);here=Path(__file__).resolve().parent
cases=[dict(kind=kind,team=team,direction=direction,px=px) for kind in ['pass','support'] for team in [0,1] for direction in [-1,1] for px in [-110,110]]
def run(profile,rom,name,s):
 p=out/(profile+'-'+name);p.mkdir(exist_ok=True);(p/'spec.json').write_text(json.dumps(s));(p/'commands.txt').write_text(f'100 load {a.state.resolve()}\n148 snap\n188 snap\n309 exit\n');env={k:v for k,v in os.environ.items() if not k.startswith('GPGX_')};env.update(GPGX_DEV='513',GPGX_HOOK=str(here/'ai_attack_gameplay_hook.py'))
 with (p/'log.txt').open('w') as log:subprocess.run(['nice','-n','19','python3',str(here/'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/'trajectory.json').read_text());passes=[x for x in rows if x['passer']==x['carrier'] and x['target']==x['receiver']];caught=[x for x in rows if x['owner']==x['receiver']];return dict(pass_frame=passes[0]['frame'] if passes else None,received_frame=caught[0]['frame'] if caught else None,open_frames=sum(x['open_slot'] for x in rows if 40<=x['frame']<=100),mean_mark_distance=round(statistics.mean(x['mark_distance'] for x in rows if 40<=x['frame']<=100),3))
def pair(s):
 name='{kind}-{team}-{direction}-{px}'.format(**s);return dict(case=name,spec=s,baseline=run('old',a.baseline,name,s),fixed=run('new',a.rom,name,s))
with ThreadPoolExecutor(max_workers=3) as pool:results=list(pool.map(pair,cases))
(out/'results.json').write_text(json.dumps(results,indent=2)+'\n')
passes=[x for x in results if x['spec']['kind']=='pass'];support=[x for x in results if x['spec']['kind']=='support'];summary=dict(baseline_passes=sum(x['baseline']['pass_frame'] is not None for x in passes),fixed_passes=sum(x['fixed']['pass_frame'] is not None for x in passes),baseline_received=sum(x['baseline']['received_frame'] is not None for x in passes),fixed_received=sum(x['fixed']['received_frame'] is not None for x in passes),baseline_open_frames=sum(x['baseline']['open_frames'] for x in support),fixed_open_frames=sum(x['fixed']['open_frames'] for x in support));(out/'summary.json').write_text(json.dumps(summary,indent=2)+'\n');print(json.dumps(summary),flush=True)
assert summary['fixed_passes']>=6 and summary['fixed_passes']>=summary['baseline_passes'],('native passes did not improve',summary)
assert summary['fixed_received']>=summary['baseline_received'],('reception worse',summary)
assert summary['fixed_open_frames']>summary['baseline_open_frames'],('support did not improve',summary)
print('PASS',len(results),'paired native attack scenarios')
