#!/usr/bin/env python3
"""Actual Hard target hooks retain shape during a valid approaching pass.
The same physical pose is compared with held possession and approaching,
receding, stopped, cleared, wrong-club and unavailable-target flight states.
"""
from pathlib import Path
import argparse,json,sys
ap=argparse.ArgumentParser();ap.add_argument('rom',type=Path);ap.add_argument('output',type=Path);ap.add_argument('--baseline',type=Path,required=True);ap.add_argument('--support',action='store_true');a=ap.parse_args();h=Path(__file__).resolve().parent;a.output.mkdir(parents=True,exist_ok=True)
def load(kind):
 text=(h/('verify_ai_'+kind+'.py')).read_text().split('\ncases=[]')[0];v='spec' if kind=='defence' else 's';d='direction' if kind=='attack' else 'orient';spaces='    ' if kind=='defence' else ' '
 target='team*6+2' if kind=='attack' else '(1-team)*6+2';sgn='1' if kind=='attack' else '-1'
 extra=f'''\n state={v}.get('pass_state','held');target={target};sender=target-1;tp=0xffb04a+128*target;sp=0xffb04a+128*sender
 px={v}.get('px',110 if '{kind}'!='gap' else 104);dep={v}.get('depth',220 if '{kind}'=='attack' else -210 if '{kind}'=='defence' else -140);ori={d}
 for addr,val in [(tp,px-10),(tp+0x14,(dep+20*({sgn}))*ori),(tp+0x34,0 if state=='keeper' else 4),(sp,140),(sp+0x14,0),(sp+0x34,3)]:body.append(f' move.w #{{val}},0x{{addr:X}}')
 body += [f' move.b #{{4 if state=="unavailable" else 0}},0x{{tp+0x63:X}}',f' move.w #{{target if state=="held" else -1}},0xFFB7AA',f' move.w #{{0xff00|target if state=="cleared" else target}},0xFFBEE0',f' move.w #{{6*(1-target//6) if state=="wrong-club" else sender}},0xFFBEDA',f' move.w #{{0 if state=="stopped" else 512 if state=="receding" else -512}},0xFFB772',f' move.w #{{0 if state=="stopped" else -512*({sgn})*ori if state=="receding" else 512*({sgn})*ori}},0xFFB774']
'''
 if kind=='defence':needle=" body += [f'    lea 0x{0xffc6ce+team*0x364:X},%a2'"
 elif kind=='gap':needle=" body += [' move.l #0x12345678,0xFFD066'"
 else:needle=" body+=[' move.l #0x11223344,%d2'"
 assert text.count(needle)==1,(kind,needle);text=text.replace(needle,extra+needle);sys.argv=['probe',str(a.rom.resolve()),str(a.output.resolve()),'--baseline',str(a.baseline.resolve())];ns={'__file__':str(h/('verify_ai_'+kind+'.py'))};exec(compile(text,kind+' flight pose probe','exec'),ns);return ns['run']
rows=[]
for kind in ['defence','gap']+(['attack'] if a.support else []):
 run=load(kind)
 def measure(rom,name,s):
  if kind=='defence':return run('flight',rom,name,s)
  if kind=='gap':return run(rom,name,s)
  return run(rom,name,s,'support')
 def position(r):return r if isinstance(r,list) else [r['x'],r['y']]
 for t in (0,1):
  for d in (-1,1):
   prefix=f'{kind}-{t}-{d}';base=dict(team=t,**({'direction':d,'role':3 if d==1 else 5} if kind=='attack' else {'orient':d}),**({'local':4} if kind=='gap' else {}));held=measure(a.rom,prefix+'-held',dict(base,pass_state='held'))
   for state in ['valid','stopped','receding','cleared','wrong-club','unavailable','keeper']:
    spec=dict(base,pass_state=state);old=measure(a.baseline,prefix+'-old-'+state,spec);new=measure(a.rom,prefix+'-new-'+state,spec)
    if state=='valid':assert position(new)==position(held) and position(new)!=position(old),(kind,spec,held,old,new)
    else:assert new==old,(kind,spec,old,new)
    rows.append(dict(kind=kind,spec=spec,held=held,baseline=old,candidate=new))
   for level in (0,2):
    spec=dict(base,pass_state='valid',difficulty=level);old=measure(a.baseline,prefix+'-old-level'+str(level),spec);new=measure(a.rom,prefix+'-new-level'+str(level),spec);assert new==old,(kind,spec,old,new);rows.append(dict(kind=kind,spec=spec,baseline=old,candidate=new))
(a.output/'results.json').write_text(json.dumps(rows,indent=2)+'\n');print('PASS',len(rows),'native pass-flight coverage/support, rejection contexts, Normal/Easy and register/RNG contracts')
