"""Bounded development search only. Holdout files are never opened here."""
import hashlib
import itertools
import json
from pathlib import Path
import numpy as np
from inputs import OUT

contract=json.loads((OUT/'execution_contract.json').read_text());clips=contract['development']
assert not set(clips)&set(contract['holdout'])
data={};source_hashes={};canon={}
for clip in clips:
    p=OUT/'work'/clip/'features.jsonl';source_hashes[clip]=hashlib.sha256(p.read_bytes()).hexdigest()
    rows=[json.loads(s) for s in p.read_text().splitlines()]
    for i,r in enumerate(rows):
        if r['displayed']:
            key=r['dedupe_key'];canon[key]=min(canon.get(key,(clip,i)),(clip,i))
    data[clip]=rows

prepared=[]
for clip,rows in data.items():
    entries=[];features=[];neighbors=[];hist={}
    for i,r in enumerate(rows):
        for p in r['pairs']:
            n=len(entries);h=hist.setdefault(p['token'],[])
            if p['reset']:h.clear()
            h[:]=[(ts,j) for ts,j in h if r['seconds']-ts<=1+1e-8];h.append((r['seconds'],n))
            neighbors.append([j for _,j in h]);entries.append(i)
            for f in p['features']:
                features.append([n,f['actor'],f['speed'],f['near'],f['approach']/f['elapsed'],f['cosine'],
                                 f['extension']/f['elapsed'],float(f['kind']=='foot'),f['vertical']])
    n=len(entries);width=max(map(len,neighbors),default=1);nb=np.full((n,width),n,dtype=np.int64)
    for i,js in enumerate(neighbors):nb[i,:len(js)]=js
    a=np.asarray(features,dtype=float).reshape(-1,9)
    selected=np.array([r['displayed'] and canon[r['dedupe_key']]==(clip,i) for i,r in enumerate(rows)])
    pos=np.array([r['reference']=='positive_reference' for r in rows])&selected
    neg=np.array([r['reference']=='negative_reference' for r in rows])&selected
    prepared.append((clip,rows,np.asarray(entries,dtype=np.int64),a,nb,pos,neg))

trials=[]
for speed,near,approach,extension,count in itertools.product((.25,.4,.55,.7,.9,1.1),(.04,.08,.14),(.06,.15,.3),(0.,.08,.2),(1,2,3)):
    cfg=dict(speed_min=speed,near_max=near,approach_speed_min=approach,extension_speed_min=extension,
             cosine_min=.45,foot_vertical_max=.4,min_samples=count,window=1.)
    result=dict(config=cfg,primary_negative=0,other_negative=0,positive=0,positive_inputs=0,by_clip={})
    for clip,rows,entries,a,nb,pos,neg in prepared:
        passing=np.zeros((len(entries)+1,2),dtype=bool)
        if len(a):
            eps=1e-12
            ok=(a[:,2]+eps>=speed)&(a[:,3]<=near+eps)&(a[:,4]+eps>=approach)&(a[:,5]+eps>=.45)&(a[:,6]+eps>=extension)&((a[:,7]==0)|(a[:,8]<=.4+eps))
            np.logical_or.at(passing,(a[:,0].astype(int),a[:,1].astype(int)),ok)
        support=passing[nb].sum(axis=1)
        hits=np.any(passing[:-1]&(support>=count),axis=1)
        hit=np.zeros(len(rows),dtype=bool);np.logical_or.at(hit,entries,hits)
        ph=int((hit&pos).sum());nh=int((hit&neg).sum())
        result['positive']+=ph;result['positive_inputs']+=int(ph>0)
        result['primary_negative' if clip.startswith(('02_','03_','14_')) else 'other_negative']+=nh
        result['by_clip'][clip]=dict(positive_hits=ph,positive_N=int(pos.sum()),negative_hits=nh,negative_N=int(neg.sum()))
    result['index']=len(trials);trials.append(result)
trials.sort(key=lambda v:(v['primary_negative'],v['other_negative'],-v['positive_inputs'],-v['positive']))
allzero=[v for v in trials if v['positive']==0]
viable=[v for v in trials if v['positive']>0]
pareto=[]
for v in viable:
    if any(u['primary_negative']<=v['primary_negative'] and u['other_negative']<=v['other_negative'] and u['positive']>=v['positive']
           and (u['primary_negative'],u['other_negative'],u['positive'])!=(v['primary_negative'],v['other_negative'],v['positive']) for u in viable):continue
    if not any((u['primary_negative'],u['other_negative'],u['positive'])==(v['primary_negative'],v['other_negative'],v['positive']) for u in pareto):pareto.append(v)
report=dict(status='DEVELOPMENT_SEARCH_COMPLETE_NOT_ACCEPTANCE',trials=len(trials),all_negative_candidates=len(allzero),
    source_hashes=source_hashes,development=clips,holdout_opened=False,dedupe='lowest clip_id per source review Frame',
    reference_labels='approximate user anchors; not exact GT; single-point anchors excluded',
    trials_data=trials,pareto=pareto)
(OUT/'reports/search.json').write_text(json.dumps(report,indent=2))
for label,items in [('CONSERVATIVE',viable[:6]),('PARETO',pareto[:18])]:
    print(label,json.dumps([{k:v[k] for k in ('index','config','primary_negative','other_negative','positive','positive_inputs','by_clip')} for v in items]),flush=True)
