#!/usr/bin/env python3
from pathlib import Path
import subprocess, json
ROOT=Path(__file__).resolve().parents[1]
QA=ROOT/'qa_screenshots'; QA.mkdir(exist_ok=True)
report=json.load(open(QA/'rc46_selective_movement_rebuild_report.json'))
summary=report['summary']
changes=report['changes']
activated=report['activatedMediapipeRuntimeLandmarks']
VIEWS={'mobile':(390,844),'ipad':(820,1180),'desktop':(1440,900)}

def html_for(name,w,h):
    mobile=name=='mobile'
    pad=14 if mobile else 28
    gap=12 if mobile else 18
    grid='grid-template-columns:1fr;' if mobile else 'grid-template-columns:1.05fr .95fr;'
    change_html=''.join(f'<div class="row"><b>{c["exerciseKey"]}</b><span>{c["action"]}</span></div>' for c in changes[:8])
    active_ex=sorted({ex for a in activated for ex in a.get('exercises',[])})
    active_html=''.join(f'<span class="badge ok">{x}</span>' for x in active_ex)
    return f'''<!doctype html><html><head><meta charset="utf-8"><style>
@page {{ size:{w}px {h}px; margin:0; }} *{{box-sizing:border-box}} body{{margin:0;width:{w}px;height:{h}px;overflow:hidden;font-family:Inter,Arial,sans-serif;background:radial-gradient(circle at 8% 0%,#174e69,#06111f 55%,#03070d);color:#effbff}}
.shell{{height:100%;padding:{pad}px;display:flex;flex-direction:column;gap:{gap}px}}.top{{display:flex;justify-content:space-between;align-items:center}}.brand{{font-weight:950;letter-spacing:.08em;font-size:{17 if mobile else 24}px}}.pill{{border:1px solid rgba(120,233,255,.42);border-radius:999px;padding:8px 12px;color:#aaf4ff;background:rgba(3,22,36,.72);font-weight:900;font-size:{10 if mobile else 13}px}}
.hero{{border:1px solid rgba(120,233,255,.22);border-radius:{20 if mobile else 30}px;background:linear-gradient(180deg,rgba(10,30,48,.72),rgba(2,8,18,.92));box-shadow:0 22px 70px rgba(0,0,0,.42);padding:{18 if mobile else 32}px}}h1{{margin:0;font-size:{31 if mobile else 54}px;line-height:1.0;letter-spacing:-.055em}}p{{margin:10px 0 0;color:#bdd3df;font-size:{12 if mobile else 17}px;line-height:1.42}}
.grid{{display:grid;{grid}gap:{gap}px;min-height:0;flex:1}}.card{{border:1px solid rgba(120,233,255,.18);border-radius:{18 if mobile else 25}px;background:rgba(5,15,29,.78);padding:{15 if mobile else 24}px;box-shadow:0 18px 55px rgba(0,0,0,.30);min-height:0;overflow:hidden}}h2{{margin:0 0 10px;font-size:{19 if mobile else 28}px}}.metrics{{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin-top:14px}}.metric{{border:1px solid rgba(255,255,255,.12);border-radius:14px;padding:{9 if mobile else 13}px;background:rgba(255,255,255,.045)}}.metric span{{display:block;color:#b8ccd8;font-size:{9 if mobile else 12}px;font-weight:800}}.metric b{{font-size:{22 if mobile else 34}px;color:#76e8ff;letter-spacing:-.05em}}.row{{display:grid;grid-template-columns:{'1fr' if mobile else '160px 1fr'};gap:5px 12px;border:1px solid rgba(255,255,255,.10);border-radius:14px;padding:{8 if mobile else 11}px;margin:8px 0;background:rgba(255,255,255,.04);font-size:{10 if mobile else 13}px}}.row b{{color:#8bffcb}}.row span{{color:#d7ebf3}}.badge{{display:inline-block;border-radius:999px;padding:7px 9px;background:rgba(120,233,255,.10);border:1px solid rgba(120,233,255,.18);font-size:{10 if mobile else 12}px;color:#c6f8ff;font-weight:800;margin:5px 5px 0 0}}.ok{{color:#8bffcb}}.warn{{color:#ffd18a}}.flow{{display:grid;grid-template-columns:repeat(5,1fr);gap:8px;margin-top:14px}}.flow div{{border:1px solid rgba(255,255,255,.11);border-radius:14px;padding:{7 if mobile else 12}px;text-align:center;color:#d7f6ff;font-weight:850;font-size:{9 if mobile else 13}px;background:rgba(255,255,255,.045)}}.footer{{display:{'none' if mobile else 'flex'};justify-content:space-between;color:#88a4b4;font-size:12px}}.mono{{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;color:#e7fbff}}
</style></head><body><main class="shell"><div class="top"><div class="brand">NEXT ATHLETE OS</div><div class="pill">RC46 · {name} QA</div></div>
<section class="hero"><h1>Selective movement rebuild</h1><p>First runtime-affecting pass where movement truth beats pose names. No images generated. Special/weak movements are gated instead of being faked.</p><div class="flow"><div>Physio truth</div><div>Foot/hand identity</div><div>Selective MediaPipe</div><div>Special gates</div><div>Runtime QA</div></div><div class="metrics"><div class="metric"><span>Sequence changes</span><b>{summary['sequenceChanges']}</b></div><div class="metric"><span>MP activations</span><b>{summary['mediapipeRuntimeLandmarkActivations']}</b></div><div class="metric"><span>Runtime changed</span><b class="ok">YES</b></div></div></section>
<section class="grid"><div class="card"><h2>Rebuilt / gated exercises</h2>{change_html}</div><div class="card"><h2>Active MediaPipe groups</h2><p>Only safe/high-confidence groups got MediaPipe runtime landmarks. Partner, prop and wrong-family throw mappings remain manual/review gated.</p><div>{active_html}</div><p>Lab: <span class="mono">tools/movement_rebuild_lab.html</span></p><p>Pass QA: <span class="mono">preview.html?v=rc46&amp;motionlab=1#pass</span></p></div></section><div class="footer"><span>Static fallback render: WeasyPrint → PNG</span><span>Chromium/Playwright not used</span></div></main></body></html>'''

for name,(w,h) in VIEWS.items():
    html=ROOT/f'qa_rc46_{name}.html'; pdf=QA/f'rc46_{name}_static_qa.pdf'; prefix=QA/f'rc46_{name}_static_qa'
    html.write_text(html_for(name,w,h),encoding='utf-8')
    subprocess.run(['weasyprint',str(html),str(pdf)],check=True,cwd=ROOT)
    subprocess.run(['pdftoppm','-png','-singlefile','-r','96',str(pdf),str(prefix)],check=True)
    print(QA/f'rc46_{name}_static_qa.png')
