"""Full /data validation of the XGBoost gate: re-score full_validation.tsv (all MEME jobs) with
meme_gate.json, produce full-corpus calibration table + 3-band structure."""
import csv, json, numpy as np, xgboost as xgb
from sklearn.metrics import roc_auc_score
D="/home/sweaver/programming/axomeme/dm3-gate-validation"
clf=xgb.XGBClassifier(); clf.load_model(f"{D}/meme_gate.json")
rows=list(csv.DictReader(open(f"{D}/full_validation.tsv"),delimiter="\t"))
X=np.array([[int(r["nseq"]),int(r["nsites"]),min(max(float(r["med_bl"]),0.001),10.0)] for r in rows],float)
y=np.array([int(int(r["sites_found_p10"])>=1) for r in rows])
s=clf.predict_proba(X)[:,1]
print(f"[FULL /data] {len(y)} jobs | base {y.mean():.3f} | AUC {roc_auc_score(y,s):.4f}")
tab=[]
print(f"{'thr':>5} {'%<t':>7} {'hit<t':>7} {'hit>=t':>7}")
for t in [0.05,0.1,0.2,0.3,0.35,0.4,0.5,0.6,0.7,0.8,0.9]:
    b=s<t; hb=float(y[b].mean()) if b.sum() else None
    tab.append({"threshold":t,"pct_below":round(100*b.mean(),1),"hit_below":round(hb,3) if hb is not None else None,"hit_above":round(float(y[~b].mean()),3)})
    print(f"{t:>5} {100*b.mean():>6.1f}% {(f'{hb:.3f}' if hb is not None else '-'):>7} {y[~b].mean():>7.3f}")
bands=[]
print("\n[3-band 0.30/0.70]")
for nm,m in [("Unlikely",s<0.30),("Uncertain",(s>=0.30)&(s<0.70)),("Likely",s>=0.70)]:
    hr=float(y[m].mean()); bands.append({"band":nm,"n":int(m.sum()),"pct":round(100*m.mean(),1),"hit_rate":round(hr,3)})
    print(f"  {nm:9} n={int(m.sum()):5d} ({100*m.mean():4.1f}%) hit {hr:.3f}")
json.dump({"universe":"all /data MEME jobs","n":len(y),"base_rate":round(float(y.mean()),3),
           "test_auc_full":round(roc_auc_score(y,s),4),"calibration_table_full":tab,"bands_030_070":bands,
           "model":"XGBoost XGBClassifier monotone_constraints=(1,1,1)"},
          open(f"{D}/calibration_full_universe.json","w"),indent=2)
print(f"\nsaved calibration_full_universe.json")
