import ctypes,importlib.util,json,os,pathlib,sys,time,statistics
from types import SimpleNamespace
import numpy as np
import scipy.linalg
from app.byte_tracking import ByteTracker
from app.contracts.frames import FrameEnvelope,DetectionObservation
R=pathlib.Path('/evidence')
s=importlib.util.spec_from_file_location('old_tracking',R/'old_tracking.py');old=importlib.util.module_from_spec(s);sys.modules[s.name]=old;s.loader.exec_module(old)
backend=[]
paths={line.split()[-1] for line in pathlib.Path('/proc/self/maps').read_text().splitlines() if 'openblas' in line and '/' in line}
for p in sorted(paths):
    lib=ctypes.CDLL(p)
    for symbol in ('openblas_get_num_threads','openblas_get_num_threads64_','scipy_openblas_get_num_threads','scipy_openblas_get_num_threads64_'):
        try:f=getattr(lib,symbol)
        except AttributeError:continue
        f.restype=ctypes.c_int
        backend.append(dict(library=pathlib.Path(p).name,threads=f()));break
assert backend,'No observable OpenBLAS backend'
frames=[]
for seq in range(35):
    f=FrameEnvelope('test','test','test','test',1,seq,seq*100000000,0,1920,1080)
    n=0 if seq in (10,11,25) else 300
    frames.append(tuple(DetectionObservation(f,'RFDETRMedium',i%12,
        (.9 if i%5==0 else .2 if i%5==1 else .05),
        ((i%20)*.04, (i//20)*.04, (i%20)*.04+.025, (i//20)*.04+.025)) for i in range(n)))
results={};outputs={}
for name,cls in [('old',old.ByteTracker),('new',ByteTracker)]:
    tracker=cls();total=[];core=[];out=[];current=[0]
    original=tracker.sv.ByteTrack
    class Wrapped:
        def __init__(self,**kwargs):self.t=original(**kwargs)
        def update_with_detections(self,d):
            t=time.perf_counter_ns();value=self.t.update_with_detections(d);current[0]+=time.perf_counter_ns()-t;return value
        def __getattr__(self,key):return getattr(self.t,key)
    tracker.sv=SimpleNamespace(ByteTrack=Wrapped,Detections=tracker.sv.Detections)
    for observations in frames:
        current[0]=0;t=time.perf_counter_ns();out.append(tracker.update(observations));elapsed=time.perf_counter_ns()-t
        total.append(elapsed/1e6);core.append(current[0]/1e6)
    tracker.reset();assert tracker.active_tracks()==0
    assert tracker.update(frames[0])==out[0]
    tracker.reset()
    outputs[name]=out
    results[name]=dict(total_mean_ms=statistics.mean(total[3:]),core_mean_ms=statistics.mean(core[3:]),adapter_mean_ms=statistics.mean([a-b for a,b in zip(total[3:],core[3:])]))
assert outputs['old']==outputs['new'],'ID parity failure'
out=dict(backend=backend,parity=True,frames=len(frames),max_candidates=300,classes=12,results=results)
(R/('bench-'+os.environ.get('OPENBLAS_NUM_THREADS','default')+'.json')).write_text(json.dumps(out,indent=2));print(json.dumps(out))
