from pathlib import Path
import csv,html
BASE=Path(__file__).resolve().parent
rows=list(csv.DictReader((BASE/'aeps-ppe-test-data.csv').open(encoding='utf-8')))
metrics=[('Thrust (mN)','thrust_mN',100,650,5,'mN'),('Specific impulse (s)','specific_impulse_s',1600,2900,.9,'% relative'),('Total efficiency (%)','total_efficiency_percent',50,72,1.7,'% relative')]
def build(width,height,mobile):
 L,R=(105,675) if mobile else (145,1320);top=230 if mobile else 220;ph=300 if mobile else 210;gap=440 if mobile else 340
 fs=21 if mobile else 17
 s=[f'<svg xmlns="http://www.w3.org/2000/svg" width="{width}" height="{height}" viewBox="0 0 {width} {height}" role="img" aria-labelledby="title desc">','<title id="title">NASA PPE Hall-thruster reference firing-condition measurements</title>','<desc id="desc">Three stacked plots show thrust, specific impulse, and total efficiency for eight NASA-reported test conditions. The horizontal positions are equally spaced condition categories, not a continuous or proportional discharge-power scale; each condition is listed below. Error bars apply the source-stated uncertainties: plus or minus 5 millinewtons, 0.9 percent relative, and 1.7 percent relative. Lines are visual guides only.</desc>','<rect width="100%" height="100%" rx="24" fill="#08172d"/>',f'<text x="42" y="65" fill="#f4f7ff" font-family="Arial,sans-serif" font-size="{32 if mobile else 29}" font-weight="700">NASA PPE Hall-thruster tests</text>',f'<text x="42" y="112" fill="#b9c8e3" font-family="Arial,sans-serif" font-size="{19 if mobile else 18}">Eight reported conditions · ETU-2 · laboratory vacuum test</text>']
 for j,(label,key,lo,hi,unc,kind) in enumerate(metrics):
  y0=top+j*gap;y1=y0+ph;s.append(f'<rect x="24" y="{y0-44}" width="{width-48}" height="{ph+104}" rx="18" fill="#112445" stroke="#364e78"/>');s.append(f'<text x="{L}" y="{y0-8}" fill="#f4f7ff" font-family="Arial,sans-serif" font-size="{23 if mobile else 21}" font-weight="700">{html.escape(label)}</text>')
  for t in range(5):
   v=lo+(hi-lo)*t/4;y=y1-(v-lo)/(hi-lo)*ph;s.append(f'<line x1="{L}" y1="{y:.1f}" x2="{R}" y2="{y:.1f}" stroke="#354a6d"/>');s.append(f'<text x="{L-12}" y="{y+6:.1f}" text-anchor="end" fill="#c6d4ea" font-family="Arial,sans-serif" font-size="{fs}">{v:.0f}' + ('%' if key=='total_efficiency_percent' else '')+'</text>')
  pts=[]
  for i,row in enumerate(rows):
   x=L+i*(R-L)/(len(rows)-1);v=float(row[key]);e=unc if kind=='mN' else v*unc/100;y=y1-(v-lo)/(hi-lo)*ph;dy=e/(hi-lo)*ph;pts.append((x,y));s.append(f'<line x1="{x:.1f}" y1="{y-dy:.1f}" x2="{x:.1f}" y2="{y+dy:.1f}" stroke="#39c3e4" stroke-width="3"/><line x1="{x-7:.1f}" y1="{y-dy:.1f}" x2="{x+7:.1f}" y2="{y-dy:.1f}" stroke="#39c3e4" stroke-width="3"/><line x1="{x-7:.1f}" y1="{y+dy:.1f}" x2="{x+7:.1f}" y2="{y+dy:.1f}" stroke="#39c3e4" stroke-width="3"/><circle cx="{x:.1f}" cy="{y:.1f}" r="7" fill="#39c3e4" stroke="#08172d" stroke-width="2"/>');s.append(f'<text x="{x:.1f}" y="{y-12:.1f}" text-anchor="middle" fill="#f4f7ff" font-family="Arial,sans-serif" font-size="{15 if mobile else 14}">{v:.0f}' + ('%' if key=='total_efficiency_percent' else '')+'</text>')
  s.append('<polyline points="'+' '.join(f'{x:.1f},{y:.1f}' for x,y in pts)+'" fill="none" stroke="#39c3e4" stroke-width="2" stroke-dasharray="7 7" opacity=".6"/>')
  for i,(x,_) in enumerate(pts):s.append(f'<text x="{x:.1f}" y="{y1+27}" text-anchor="middle" fill="#c6d4ea" font-family="Arial,sans-serif" font-size="{fs}">{i+1}</text>')
  s.append(f'<text x="{(L+R)/2}" y="{y1+55}" text-anchor="middle" fill="#c6d4ea" font-family="Arial,sans-serif" font-size="{fs}">Test condition number (see key)</text>')
 foot=height-20;s.append(f'<text x="30" y="{foot}" fill="#b9c8e3" font-family="Arial,sans-serif" font-size="{16 if mobile else 15}">Reported uncertainty: ±5 mN; ±0.9% Isp; ±1.7% efficiency. Focused y-axes.</text>');s.append('</svg>');return '\n'.join(s)+'\n'
(BASE/'aeps-ppe-performance.svg').write_text(build(1400,1300,False),encoding='utf-8')
(BASE/'aeps-ppe-performance-mobile.svg').write_text(build(780,1660,True),encoding='utf-8')
print('Rendered exact-table PPE values:',len(rows),'conditions')
