#!/usr/bin/env python3
from __future__ import annotations
import json, pathlib, subprocess
ROOT=pathlib.Path(__file__).resolve().parents[1]
QA=ROOT/'qa_screenshots'
RC49=ROOT/'assets/data/image-admin/rc49_special_prop_binding.json'
TRACE=ROOT/'assets/data/image-admin/rc49_motion_trace_verification.json'
QA.mkdir(exist_ok=True)
rc49=json.loads(RC49.read_text(encoding='utf-8'))
trace=json.loads(TRACE.read_text(encoding='utf-8'))

def esc(s):
    return str(s).replace('&','&amp;').replace('<','&lt;').replace('>','&gt;').replace('"','&quot;').replace("'",'&#39;')

def make_html(name,w,h):
    s=trace['summary']; c=s['counts']; sp=s['special']; mp=rc49['medballMediaPipeActivation']
    cards=[('Seq changes',rc49['sequenceChanges']),('Prop frames',sp['propBoundFrames']),('Medball active',mp['activated']),('Medball held',mp['skipped']),('Trace errors',s['issues']['error']),('Missing anchors',c['missingAnchors']),('Low-conf active',c['lowConfidenceActiveAnchors']),('Special gate errors',c['specialGateErrors'])]
    cards_html=''.join(f"<div class='metric'><b>{esc(v)}</b><span>{esc(k)}</span></div>" for k,v in cards)
    changes=''.join(f"<div class='ex'><b>{esc(x['exerciseKey'])}</b><span>{esc(x['runtimeGate'])}</span><em>{esc(x['action'])}</em><small>{esc(x['runtimeImpact'])}</small></div>" for x in rc49.get('changes',[]))
    held=''.join(f"<span>{esc(x)}</span>" for x in rc49.get('heldOrManual',[]))
    skipped=''.join(f"<li><b>{esc(x['poseKey'])}</b> {esc(x['athleteId'])} · confidence {esc(x['minConfidence'])}</li>" for x in mp.get('skippedItems',[])) or '<li>None</li>'
    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;background:linear-gradient(135deg,#061320,#0d3143 58%,#020617);color:#ecfeff;font-family:Inter,system-ui,-apple-system,Segoe UI,sans-serif}}.wrap{{padding:{max(20,int(w*.034))}px}}.hero{{border:1px solid rgba(125,211,252,.34);border-radius:26px;padding:22px;background:rgba(10,35,50,.74)}}.eyebrow{{color:#67e8f9;font-size:13px;text-transform:uppercase;font-weight:900;letter-spacing:.16em}}h1{{font-size:{max(36,int(w*.055))}px;letter-spacing:-.055em;line-height:.92;margin:8px 0 12px}}p{{font-size:{max(15,int(w*.017))}px;color:#cfe7f0;margin:0;max-width:980px}}.grid{{display:grid;grid-template-columns:repeat({2 if w<700 else 4},1fr);gap:12px;margin:18px 0}}.metric{{border:1px solid rgba(125,211,252,.2);border-radius:18px;padding:14px;background:rgba(8,25,38,.68)}}.metric b{{display:block;font-size:{max(22,int(w*.028))}px;color:#86efac}}.metric span{{color:#aecbd8;font-size:12px}}h2{{font-size:{max(20,int(w*.024))}px;margin:18px 0 10px}}.exwrap{{display:grid;grid-template-columns:repeat({1 if w<700 else 3},1fr);gap:10px}}.ex{{border:1px solid rgba(125,211,252,.18);border-radius:16px;background:rgba(4,18,29,.72);padding:12px;min-height:92px}}.ex b{{font-size:15px;display:block}}.ex span{{display:inline-block;color:#fbbf24;font-size:11px;border:1px solid rgba(251,191,36,.32);border-radius:999px;padding:3px 7px;margin:5px 0}}.ex em{{display:block;font-style:normal;color:#d9fbff;font-size:12px}}.ex small{{display:block;color:#9fb8c5;font-size:11px;margin-top:5px}}.held{{display:flex;gap:8px;flex-wrap:wrap}}.held span{{border:1px solid rgba(251,191,36,.3);border-radius:999px;padding:6px 9px;color:#fbbf24;background:rgba(251,191,36,.07);font-size:12px;font-weight:800}}ul{{margin:8px 0 0;padding:0;list-style:none;display:grid;grid-template-columns:repeat({1 if w<700 else 3},1fr);gap:8px}}li{{border:1px solid rgba(251,191,36,.25);padding:10px;border-radius:14px;background:rgba(18,56,77,.45);font-size:13px}}.footer{{position:absolute;left:{max(20,int(w*.034))}px;right:{max(20,int(w*.034))}px;bottom:14px;color:#8cb5c4;font-size:12px}}
</style></head><body><div class='wrap'><section class='hero'><div class='eyebrow'>NEXT Pose Atlas · {esc(name)}</div><h1>RC49 Special Prop Binding</h1><p>{esc(rc49['principle'])}</p></section><div class='grid'>{cards_html}</div><h2>Special movement decisions</h2><div class='exwrap'>{changes}</div><h2>Held/manual gates</h2><div class='held'>{held}</div><h2>Medball frames held by confidence gate</h2><ul>{skipped}</ul></div><div class='footer'>Static fallback QA · app animation not browser-tested in sandbox · {esc(rc49['createdAt'])}</div></body></html>"""

def render(name,w,h):
    html=QA/f'rc49_{name}_static_qa.html'; pdf=QA/f'rc49_{name}_static_qa.pdf'; png=QA/f'rc49_{name}_static_qa'
    html.write_text(make_html(name,w,h),encoding='utf-8')
    subprocess.run(['weasyprint',str(html),str(pdf)],check=True)
    subprocess.run(['pdftoppm','-png','-singlefile','-r','144',str(pdf),str(png)],check=True)
for args in [('mobile',390,844),('ipad',820,1180),('desktop',1180,820)]: render(*args)
print('Rendered RC49 QA screenshots to',QA)
