"""Lab 2 charts. Inputs: results/<run>/*.jsonl, grades.json, official-domains.json."""
import json,statistics as st,sys,collections
RUN=sys.argv[1]; OUT=sys.argv[2]
P=['exa','firecrawl','tavily']; NAME={'exa':'Exa','firecrawl':'Firecrawl','tavily':'Tavily'}
COL={'exa':'#0e7c7b','firecrawl':'#475569','tavily':'#b05525'}
F='font-family="IBM Plex Sans, Inter, system-ui, sans-serif"'
rows={p:[json.loads(l) for l in open(f'{RUN}/{p}.jsonl')] for p in P}
OFF=set(json.load(open('official-domains.json')))
dom=lambda u:(u or '').split('/')[2].replace('www.','') if '://' in (u or '') else ''
isoff=lambda u:any(dom(u)==d or dom(u).endswith('.'+d) for d in OFF)
def svg(w,h,title,desc,body):
    return f'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 {w} {h}" width="100%" role="img" aria-labelledby="t d"><title id="t">{title}</title><desc id="d">{desc}</desc><rect width="{w}" height="{h}" rx="12" fill="#ffffff"/>{body}</svg>\n'
def hbars(fname,title,heading,vals,maxv,fmt,note):
    w,h=1200,630; x0=230; bw=900
    b=f'<text x="48" y="78" {F} font-size="34" font-weight="600" fill="#0f172a">{heading}</text>'
    for i,(p,v) in enumerate(vals):
        y=140+i*130; L=bw*v/maxv; inside=L>330
        b+=(f'<text x="48" y="{y+50}" {F} font-size="28" fill="#334155">{NAME[p]}</text>'
            f'<rect x="{x0}" y="{y+12}" width="{bw}" height="60" rx="8" fill="#e2e8f0"/>'
            f'<rect x="{x0}" y="{y+12}" width="{L:.1f}" height="60" rx="8" fill="{COL[p]}"/>'
            f'<text x="{x0+L-18 if inside else x0+L+14:.1f}" y="{y+52}" {F} font-size="28" font-weight="600" fill="{"#ffffff" if inside else "#0f172a"}" text-anchor="{"end" if inside else "start"}">{fmt(v)}</text>')
    b+=f'<text x="48" y="{h-36}" {F} font-size="22" fill="#64748b">{note}</text>'
    desc='; '.join(f'{NAME[p]}: {fmt(v)}' for p,v in vals)
    open(f'{OUT}/{fname}','w').write(svg(w,h,title,desc,b))
# 1 official sources in top 3 (all 50 queries)
off={p:sum(isoff(it['url']) for r in rows[p] for it in r['results'][:3]) for p in P}
vals=sorted(off.items(),key=lambda x:-x[1])
hbars('official-sources.svg','Official sources in the top 3 results','Top-3 results from the vendor\'s own site or docs (of 150)',vals,150,lambda v:f'{v} of 150 ({v/150:.0%})','50 queries x top 3 results per API. Pondero Labs, October 19, 2026.')
# 2 median latency
med={p:st.median(r['ms'] for r in rows[p] if r['status']==200) for p in P}
vals=sorted(med.items(),key=lambda x:x[1])
hbars('latency.svg','Median response time per search','Median response time per search (lower is faster)',vals,2000,lambda v:f'{v/1000:.2f} s','50 searches per API from one server in Germany. Pondero Labs, October 19, 2026.')
# 3 graded quality
g=json.load(open('grades.json'))['grades']
q={p:sum(v[p][0] for v in g.values()) for p in P}
vals=sorted(q.items(),key=lambda x:-x[1])
hbars('quality.svg','Answer quality score','Answer quality on 20 graded queries (max 40)',vals,40,lambda v:f'{v} / 40','2 = official current source answers it in the top 3, 1 = secondary or outdated, 0 = not answered.')
print(off,med,q)
