"""Lock an existing native system target and observe its original direction getter; no flight input."""
import argparse
import hashlib
import json
from pathlib import Path
import time
import frida

p=argparse.ArgumentParser(description=__doc__)
p.add_argument('--pid',type=int,required=True)
p.add_argument('--profile',type=Path,required=True)
p.add_argument('--snapshot',type=Path,required=True)
p.add_argument('--thread',type=int,required=True)
p.add_argument('--target',required=True)
p.add_argument('--output',type=Path,required=True)
a=p.parse_args()
profile=json.loads(a.profile.read_text(encoding='utf-8-sig'))
snapshot=json.loads(a.snapshot.read_text(encoding='utf-8-sig'))
if snapshot['pid']!=a.pid or snapshot['gameSha256']!=profile['sha256'] or hashlib.sha256(Path(profile['image']).read_bytes()).hexdigest()!=profile['sha256']:
    raise SystemExit('Selected process/build does not match the observation snapshot')
targets=[r for r in snapshot['navigationRecords']['records'] if r['name']==a.target and r['type']==2 and r['kind']==0]
if len(targets)!=1:raise SystemExit('A unique existing game system target is required')
bindings={'pid':a.pid,'entity':snapshot['player']['entityId'],'pose':snapshot['poseLookup']['poseAddress'],
          'fsd':next(x for x in snapshot['components'] if x['name']=='fsd')['address'],
          'life':next(x for x in snapshot['components'] if x['name']=='fsd')['lifecycle'],
          'navigation':next(x for x in snapshot['fsdSources'] if x['name']=='navigationTarget')['address'],
          'physics':snapshot['physics'][0]['address'],'inputRoot':snapshot['physics'][0]['inputRoot'],
          'thread':a.thread,'target':{k:targets[0][k] for k in ['key','worldAddress','name']}}
source='const PROFILE='+json.dumps(profile)+';const BINDINGS='+json.dumps(bindings)+';\n'+Path(__file__).with_name('navigation-target-probe.js').read_text(encoding='utf-8')
a.output.parent.mkdir(parents=True,exist_ok=True)
counts={};errors=[]
with a.output.open('x',encoding='utf-8') as out:
    session=frida.attach(a.pid)
    try:
        script=session.create_script(source)
        def message(m,data):
            row=m.get('payload') if m['type']=='send' else {'kind':'error','detail':m}
            out.write(json.dumps(row)+'\n');out.flush();counts[row.get('kind','unknown')]=counts.get(row.get('kind','unknown'),0)+1
            if row.get('kind')=='error':errors.append(row)
            if row.get('kind') in ['original-target-lock','error']:print(json.dumps(row),flush=True)
        script.on('message',message);script.load()
        deadline=time.monotonic()+12
        while time.monotonic()<deadline and not errors:time.sleep(.1)
        script.unload()
    finally:session.detach()
print(json.dumps({'counts':counts,'errors':errors,'screenUse':False,'fsdInputsSent':0,'throttleInputsSent':0}))
